1: /* unofficial gameplaySP kai
2: *
3: * Copyright (C) 2006 Exophase <exophase@gmail.com>
4: * Copyright (C) 2007 takka <takka@tfact.net>
5: * Copyright (C) 2007 ????? <?????>
6: *
7: * This program is free software; you can redistribute it and/or
8: * modify it under the terms of the GNU General Public License as
9: * published by the Free Software Foundation; either version 2 of
10: * the License, or (at your option) any later version.
11: *
12: * This program is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15: * General Public License for more details.
16: *
17: * You should have received a copy of the GNU General Public License
18: * along with this program; if not, write to the Free Software
19: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20: */
21:
22: // Important todo:
23: // - stm reglist writeback when base is in the list needs adjustment
24: // - block memory needs psr swapping and user mode reg swapping
25:
26: #include "common.h"
27:
28: u32 memory_region_access_read_u8[16];
29: u32 memory_region_access_read_s8[16];
30: u32 memory_region_access_read_u16[16];
31: u32 memory_region_access_read_s16[16];
32: u32 memory_region_access_read_u32[16];
33: u32 memory_region_access_write_u8[16];
34: u32 memory_region_access_write_u16[16];
35: u32 memory_region_access_write_u32[16];
36: u32 memory_reads_u8;
37: u32 memory_reads_s8;
38: u32 memory_reads_u16;
39: u32 memory_reads_s16;
40: u32 memory_reads_u32;
41: u32 memory_writes_u8;
42: u32 memory_writes_u16;
43: u32 memory_writes_u32;
44:
45: u32 reg_tmp;
46:
47: const u8 bit_count[256] =
48: {
49: 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
50: 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
51: 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
52: 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
53: 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
54: 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
55: 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
56: 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
57: 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
58: 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
59: 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
60: 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
61: 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
62: 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
63: 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
64: 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
65: };
66:
67: const u32 psr_masks[16] =
68: {
69: 0x00000000, 0x000000FF, 0x0000FF00, 0x0000FFFF, 0x00FF0000,
70: 0x00FF00FF, 0x00FFFF00, 0x00FFFFFF, 0xFF000000, 0xFF0000FF,
71: 0xFF00FF00, 0xFF00FFFF, 0xFFFF0000, 0xFFFF00FF, 0xFFFFFF00,
72: 0xFFFFFFFF
73: };
74:
75: // When a mode change occurs from non-FIQ to non-FIQ retire the current
76: // reg[13] and reg[14] into reg_mode[cpu_mode][5] and reg_mode[cpu_mode][6]
77: // respectively and load into reg[13] and reg[14] reg_mode[new_mode][5] and
78: // reg_mode[new_mode][6]. When swapping to/from FIQ retire/load reg[8]
79: // through reg[14] to/from reg_mode[MODE_FIQ][0] through reg_mode[MODE_FIQ][6].
80:
81: u32 reg_mode[7][7];
82:
83: u32 cpu_modes[32] =
84: {
85: MODE_INVALID, MODE_INVALID, MODE_INVALID , MODE_INVALID , MODE_INVALID,
86: MODE_INVALID, MODE_INVALID, MODE_INVALID , MODE_INVALID , MODE_INVALID,
87: MODE_INVALID, MODE_INVALID, MODE_INVALID , MODE_INVALID , MODE_INVALID,
88: MODE_INVALID, MODE_USER , MODE_FIQ , MODE_IRQ , MODE_SUPERVISOR,
89: MODE_INVALID, MODE_INVALID, MODE_INVALID , MODE_ABORT , MODE_INVALID,
90: MODE_INVALID, MODE_INVALID, MODE_UNDEFINED,MODE_INVALID , MODE_INVALID,
91: MODE_INVALID, MODE_USER
92: };
93:
94: u32 cpu_modes_cpsr[7] = { 0x10, 0x11, 0x12, 0x13, 0x17, 0x1B, 0x1F };
95:
96: // When switching modes set spsr[new_mode] to cpsr. Modifying PC as the
97: // target of a data proc instruction will set cpsr to spsr[cpu_mode].
98: u32 spsr[6];
99:
100: // ARM/Thumb mode is stored in the flags directly, this is simpler than
101: // shadowing it since it has a constant 1bit represenation.
102:
103: char *reg_names[16] =
104: {
105: " r0", " r1", " r2", " r3", " r4", " r5", " r6", " r7",
106: " r8", " r9", "r10", " fp", " ip", " sp", " lr", " pc"
107: };
108:
109: u32 instruction_count = 0;
110:
111: u32 output_field = 0;
112:
113: u32 init_screen = 1;
114: u32 last_instruction = 0;
115:
116: void init_cpu()
117: {
118: u32 i;
119:
120: for(i = 0; i < 16; i++)
121: {
122: reg[i] = 0;
123: }
124:
125: reg[REG_SP] = 0x03007F00;
126: reg[REG_PC] = 0x08000000;
127: reg[REG_CPSR] = 0x0000001F;
128: reg[CPU_HALT_STATE] = CPU_ACTIVE;
129: reg[CPU_MODE] = MODE_USER;
130: reg[CHANGED_PC_STATUS] = 0;
131:
132: reg_mode[MODE_USER][5] = 0x03007F00;
133: reg_mode[MODE_IRQ][5] = 0x03007FA0;
134: reg_mode[MODE_FIQ][5] = 0x03007FA0;
135: reg_mode[MODE_SUPERVISOR][5] = 0x03007FE0;
136: }
137:
138: #define cpu_savestate_body(type) \
139: { \
140: FILE_##type(savestate_file, reg, 0x100); \
141: FILE_##type##_ARRAY(savestate_file, spsr); \
142: FILE_##type##_ARRAY(savestate_file, reg_mode); \
143: } \
144:
145: void cpu_read_savestate(FILE_TAG_TYPE savestate_file)
146: cpu_savestate_body(READ);
147:
148: void cpu_read_mem_savestate(FILE_TAG_TYPE savestate_file)
149: cpu_savestate_body(READ_MEM);
150:
151: void cpu_write_mem_savestate(FILE_TAG_TYPE savestate_file)
152: cpu_savestate_body(WRITE_MEM);
153:
154: #ifdef C_CORE_MODE
155:
156: #define arm_decode_data_proc_reg() \
157: u32 rn = (opcode >> 16) & 0x0F; \
158: u32 rd = (opcode >> 12) & 0x0F; \
159: u32 rm = opcode & 0x0F \
160:
161: #define arm_decode_data_proc_imm() \
162: u32 rn = (opcode >> 16) & 0x0F; \
163: u32 rd = (opcode >> 12) & 0x0F; \
164: u32 imm; \
165: ROR(imm, opcode & 0xFF, ((opcode >> 8) & 0x0F) * 2) \
166:
167: #define arm_decode_psr_reg() \
168: u32 psr_field = (opcode >> 16) & 0x0F; \
169: u32 rd = (opcode >> 12) & 0x0F; \
170: u32 rm = opcode & 0x0F \
171:
172: #define arm_decode_psr_imm() \
173: u32 psr_field = (opcode >> 16) & 0x0F; \
174: u32 rd = (opcode >> 12) & 0x0F; \
175: u32 imm; \
176: ROR(imm, opcode & 0xFF, ((opcode >> 8) & 0x0F) * 2) \
177:
178: #define arm_decode_branchx() \
179: u32 rn = opcode & 0x0F \
180:
181: #define arm_decode_multiply() \
182: u32 rd = (opcode >> 16) & 0x0F; \
183: u32 rn = (opcode >> 12) & 0x0F; \
184: u32 rs = (opcode >> 8) & 0x0F; \
185: u32 rm = opcode & 0x0F \
186:
187: #define arm_decode_multiply_long() \
188: u32 rdhi = (opcode >> 16) & 0x0F; \
189: u32 rdlo = (opcode >> 12) & 0x0F; \
190: u32 rn = (opcode >> 8) & 0x0F; \
191: u32 rm = opcode & 0x0F \
192:
193: #define arm_decode_swap() \
194: u32 rn = (opcode >> 16) & 0x0F; \
195: u32 rd = (opcode >> 12) & 0x0F; \
196: u32 rm = opcode & 0x0F \
197:
198: #define arm_decode_half_trans_r() \
199: u32 rn = (opcode >> 16) & 0x0F; \
200: u32 rd = (opcode >> 12) & 0x0F; \
201: u32 rm = opcode & 0x0F \
202:
203: #define arm_decode_half_trans_of() \
204: u32 rn = (opcode >> 16) & 0x0F; \
205: u32 rd = (opcode >> 12) & 0x0F; \
206: u32 offset = ((opcode >> 4) & 0xF0) | (opcode & 0x0F) \
207:
208: #define arm_decode_data_trans_imm() \
209: u32 rn = (opcode >> 16) & 0x0F; \
210: u32 rd = (opcode >> 12) & 0x0F; \
211: u32 offset = opcode & 0x0FFF \
212:
213: #define arm_decode_data_trans_reg() \
214: u32 rn = (opcode >> 16) & 0x0F; \
215: u32 rd = (opcode >> 12) & 0x0F; \
216: u32 rm = opcode & 0x0F \
217:
218: #define arm_decode_block_trans() \
219: u32 rn = (opcode >> 16) & 0x0F; \
220: u32 reg_list = opcode & 0xFFFF \
221:
222: #define arm_decode_branch() \
223: s32 offset = ((s32)(opcode & 0xFFFFFF) << 8) >> 6 \
224:
225: #define calculate_z_flag(dest) \
226: z_flag = ((dest) == 0) \
227:
228: #define calculate_n_flag(dest) \
229: n_flag = ((signed)(dest) < 0) \
230:
231: #define calculate_c_flag_sub(dest, src_a, src_b) \
232: c_flag = ((unsigned)(src_b) <= (unsigned)(src_a)) \
233:
234: #define calculate_v_flag_sub(dest, src_a, src_b) \
235: v_flag = ((signed)(src_b) > (signed)(src_a)) != ((signed)(dest) < 0) \
236:
237: #define calculate_c_flag_add(dest, src_a, src_b) \
238: c_flag = ((unsigned)(dest) < (unsigned)(src_a)) \
239:
240: #define calculate_v_flag_add(dest, src_a, src_b) \
241: v_flag = ((signed)(dest) < (signed)(src_a)) != ((signed)(src_b) < 0) \
242:
243: #define get_shift_register(dest) \
244: u32 shift = reg[(opcode >> 8) & 0x0F]; \
245: dest = reg[rm]; \
246: if(rm == 15) \
247: dest += 4 \
248:
249: #define calculate_reg_sh() \
250: u32 reg_sh = 0; \
251: switch((opcode >> 4) & 0x07) \
252: { \
253: /* LSL imm */ \
254: case 0x0: \
255: { \
256: reg_sh = reg[rm] << ((opcode >> 7) & 0x1F); \
257: break; \
258: } \
259: \
260: /* LSL reg */ \
261: case 0x1: \
262: { \
263: get_shift_register(reg_sh); \
264: if(shift <= 31) \
265: reg_sh = reg_sh << shift; \
266: else \
267: reg_sh = 0; \
268: break; \
269: } \
270: \
271: /* LSR imm */ \
272: case 0x2: \
273: { \
274: u32 imm = (opcode >> 7) & 0x1F; \
275: if(imm == 0) \
276: reg_sh = 0; \
277: else \
278: reg_sh = reg[rm] >> imm; \
279: break; \
280: } \
281: \
282: /* LSR reg */ \
283: case 0x3: \
284: { \
285: get_shift_register(reg_sh); \
286: if(shift <= 31) \
287: reg_sh = reg_sh >> shift; \
288: else \
289: reg_sh = 0; \
290: break; \
291: } \
292: \
293: /* ASR imm */ \
294: case 0x4: \
295: { \
296: u32 imm = (opcode >> 7) & 0x1F; \
297: reg_sh = reg[rm]; \
298: \
299: if(imm == 0) \
300: reg_sh = (s32)reg_sh >> 31; \
301: else \
302: reg_sh = (s32)reg_sh >> imm; \
303: break; \
304: } \
305: \
306: /* ASR reg */ \
307: case 0x5: \
308: { \
309: get_shift_register(reg_sh); \
310: if(shift <= 31) \
311: reg_sh = (s32)reg_sh >> shift; \
312: else \
313: reg_sh = (s32)reg_sh >> 31; \
314: break; \
315: } \
316: \
317: /* ROR imm */ \
318: case 0x6: \
319: { \
320: u32 imm = (opcode >> 7) & 0x1F; \
321: \
322: if(imm == 0) \
323: reg_sh = (reg[rm] >> 1) | (c_flag << 31); \
324: else \
325: ROR(reg_sh, reg[rm], imm); \
326: break; \
327: } \
328: \
329: /* ROR reg */ \
330: case 0x7: \
331: { \
332: get_shift_register(reg_sh); \
333: ROR(reg_sh, reg_sh, shift); \
334: break; \
335: } \
336: } \
337:
338: #define calculate_reg_sh_flags() \
339: u32 reg_sh = 0; \
340: switch((opcode >> 4) & 0x07) \
341: { \
342: /* LSL imm */ \
343: case 0x0: \
344: { \
345: u32 imm = (opcode >> 7) & 0x1F; \
346: reg_sh = reg[rm]; \
347: \
348: if(imm != 0) \
349: { \
350: c_flag = (reg_sh >> (32 - imm)) & 0x01; \
351: reg_sh <<= imm; \
352: } \
353: \
354: break; \
355: } \
356: \
357: /* LSL reg */ \
358: case 0x1: \
359: { \
360: get_shift_register(reg_sh); \
361: if(shift != 0) \
362: { \
363: if(shift > 31) \
364: { \
365: if(shift == 32) \
366: c_flag = reg_sh & 0x01; \
367: else \
368: c_flag = 0; \
369: reg_sh = 0; \
370: } \
371: else \
372: { \
373: c_flag = (reg_sh >> (32 - shift)) & 0x01; \
374: reg_sh <<= shift; \
375: } \
376: } \
377: break; \
378: } \
379: \
380: /* LSR imm */ \
381: case 0x2: \
382: { \
383: u32 imm = (opcode >> 7) & 0x1F; \
384: reg_sh = reg[rm]; \
385: if(imm == 0) \
386: { \
387: c_flag = reg_sh >> 31; \
388: reg_sh = 0; \
389: } \
390: else \
391: { \
392: c_flag = (reg_sh >> (imm - 1)) & 0x01; \
393: reg_sh >>= imm; \
394: } \
395: break; \
396: } \
397: \
398: /* LSR reg */ \
399: case 0x3: \
400: { \
401: get_shift_register(reg_sh); \
402: if(shift != 0) \
403: { \
404: if(shift > 31) \
405: { \
406: if(shift == 32) \
407: c_flag = (reg_sh >> 31) & 0x01; \
408: else \
409: c_flag = 0; \
410: reg_sh = 0; \
411: } \
412: else \
413: { \
414: c_flag = (reg_sh >> (shift - 1)) & 0x01; \
415: reg_sh >>= shift; \
416: } \
417: } \
418: break; \
419: } \
420: \
421: /* ASR imm */ \
422: case 0x4: \
423: { \
424: u32 imm = (opcode >> 7) & 0x1F; \
425: reg_sh = reg[rm]; \
426: if(imm == 0) \
427: { \
428: reg_sh = (s32)reg_sh >> 31; \
429: c_flag = reg_sh & 0x01; \
430: } \
431: else \
432: { \
433: c_flag = (reg_sh >> (imm - 1)) & 0x01; \
434: reg_sh = (s32)reg_sh >> imm; \
435: } \
436: break; \
437: } \
438: \
439: /* ASR reg */ \
440: case 0x5: \
441: { \
442: get_shift_register(reg_sh); \
443: if(shift != 0) \
444: { \
445: if(shift > 31) \
446: { \
447: reg_sh = (s32)reg_sh >> 31; \
448: c_flag = reg_sh & 0x01; \
449: } \
450: else \
451: { \
452: c_flag = (reg_sh >> (shift - 1)) & 0x01; \
453: reg_sh = (s32)reg_sh >> shift; \
454: } \
455: } \
456: break; \
457: } \
458: \
459: /* ROR imm */ \
460: case 0x6: \
461: { \
462: u32 imm = (opcode >> 7) & 0x1F; \
463: reg_sh = reg[rm]; \
464: if(imm == 0) \
465: { \
466: u32 old_c_flag = c_flag; \
467: c_flag = reg_sh & 0x01; \
468: reg_sh = (reg_sh >> 1) | (old_c_flag << 31); \
469: } \
470: else \
471: { \
472: c_flag = (reg_sh >> (imm - 1)) & 0x01; \
473: ROR(reg_sh, reg_sh, imm); \
474: } \
475: break; \
476: } \
477: \
478: /* ROR reg */ \
479: case 0x7: \
480: { \
481: get_shift_register(reg_sh); \
482: if(shift != 0) \
483: { \
484: c_flag = (reg_sh >> (shift - 1)) & 0x01; \
485: ROR(reg_sh, reg_sh, shift); \
486: } \
487: break; \
488: } \
489: } \
490:
491: #define calculate_reg_offset() \
492: u32 reg_offset = 0; \
493: switch((opcode >> 5) & 0x03) \
494: { \
495: /* LSL imm */ \
496: case 0x0: \
497: { \
498: reg_offset = reg[rm] << ((opcode >> 7) & 0x1F); \
499: break; \
500: } \
501: \
502: /* LSR imm */ \
503: case 0x1: \
504: { \
505: u32 imm = (opcode >> 7) & 0x1F; \
506: if(imm == 0) \
507: reg_offset = 0; \
508: else \
509: reg_offset = reg[rm] >> imm; \
510: break; \
511: } \
512: \
513: /* ASR imm */ \
514: case 0x2: \
515: { \
516: u32 imm = (opcode >> 7) & 0x1F; \
517: if(imm == 0) \
518: reg_offset = (s32)reg[rm] >> 31; \
519: else \
520: reg_offset = (s32)reg[rm] >> imm; \
521: break; \
522: } \
523: \
524: /* ROR imm */ \
525: case 0x3: \
526: { \
527: u32 imm = (opcode >> 7) & 0x1F; \
528: if(imm == 0) \
529: reg_offset = (reg[rm] >> 1) | (c_flag << 31); \
530: else \
531: ROR(reg_offset, reg[rm], imm); \
532: break; \
533: } \
534: } \
535:
536: #define calculate_flags_add(dest, src_a, src_b) \
537: calculate_z_flag(dest); \
538: calculate_n_flag(dest); \
539: calculate_c_flag_add(dest, src_a, src_b); \
540: calculate_v_flag_add(dest, src_a, src_b) \
541:
542: #define calculate_flags_sub(dest, src_a, src_b) \
543: calculate_z_flag(dest); \
544: calculate_n_flag(dest); \
545: calculate_c_flag_sub(dest, src_a, src_b); \
546: calculate_v_flag_sub(dest, src_a, src_b) \
547:
548: #define calculate_flags_logic(dest) \
549: calculate_z_flag(dest); \
550: calculate_n_flag(dest) \
551:
552: #define extract_flags() \
553: n_flag = reg[REG_CPSR] >> 31; \
554: z_flag = (reg[REG_CPSR] >> 30) & 0x01; \
555: c_flag = (reg[REG_CPSR] >> 29) & 0x01; \
556: v_flag = (reg[REG_CPSR] >> 28) & 0x01 \
557:
558: #define collapse_flags() \
559: reg[REG_CPSR] = (n_flag << 31) | (z_flag << 30) | (c_flag << 29) | \
560: (v_flag << 28) | (reg[REG_CPSR] & ~0xF0000000) \
561:
562: #define memory_region(r_dest, l_dest, address) \
563: r_dest = memory_regions[(address) >> 24]; \
564: l_dest = memory_limits[(address) >> 24] \
565:
566: #define pc_region() \
567: memory_region(pc_region, pc_limit, pc) \
568:
569: #define check_pc_region() \
570: new_pc_region = (pc >> 15); \
571: if(new_pc_region != pc_region) \
572: { \
573: pc_region = new_pc_region; \
574: pc_address_block = memory_map_read[new_pc_region]; \
575: \
576: if(pc_address_block == NULL) \
577: pc_address_block = load_gamepak_page(pc_region & 0x3FF); \
578: } \
579:
580: u32 branch_targets = 0;
581: u32 high_frequency_branch_targets = 0;
582:
583: #define BRANCH_ACTIVITY_THRESHOLD 50
584:
585: #define arm_update_pc() \
586: pc = reg[REG_PC] \
587:
588: #define arm_pc_offset(val) \
589: pc += val; \
590: reg[REG_PC] = pc \
591:
592: #define arm_pc_offset_update(val) \
593: pc += val; \
594: reg[REG_PC] = pc \
595:
596: #define arm_pc_offset_update_direct(val) \
597: pc = val; \
598: reg[REG_PC] = pc \
599:
600:
601: // It should be okay to still generate result flags, spsr will overwrite them.
602: // This is pretty infrequent (returning from interrupt handlers, et al) so
603: // probably not worth optimizing for.
604:
605: #define check_for_interrupts() \
606: if((io_registers[REG_IE] & io_registers[REG_IF]) && \
607: io_registers[REG_IME] && ((reg[REG_CPSR] & 0x80) == 0)) \
608: { \
609: reg_mode[MODE_IRQ][6] = reg[REG_PC] + 4; \
610: spsr[MODE_IRQ] = reg[REG_CPSR]; \
611: reg[REG_CPSR] = 0xD2; \
612: reg[REG_PC] = 0x00000018; \
613: arm_update_pc(); \
614: set_cpu_mode(MODE_IRQ); \
615: goto arm_loop; \
616: } \
617:
618: #define arm_spsr_restore() \
619: if(rd == 15) \
620: { \
621: if(reg[CPU_MODE] != MODE_USER) \
622: { \
623: reg[REG_CPSR] = spsr[reg[CPU_MODE]]; \
624: extract_flags(); \
625: set_cpu_mode(cpu_modes[reg[REG_CPSR] & 0x1F]); \
626: check_for_interrupts(); \
627: } \
628: arm_update_pc(); \
629: \
630: if(reg[REG_CPSR] & 0x20) \
631: goto thumb_loop; \
632: } \
633:
634: #define arm_data_proc_flags_reg() \
635: arm_decode_data_proc_reg(); \
636: calculate_reg_sh_flags() \
637:
638: #define arm_data_proc_reg() \
639: arm_decode_data_proc_reg(); \
640: calculate_reg_sh() \
641:
642: #define arm_data_proc_flags_imm() \
643: arm_decode_data_proc_imm() \
644:
645: #define arm_data_proc_imm() \
646: arm_decode_data_proc_imm() \
647:
648: #define arm_data_proc(expr, type) \
649: { \
650: u32 dest; \
651: arm_pc_offset(8); \
652: arm_data_proc_##type(); \
653: dest = expr; \
654: arm_pc_offset(-4); \
655: reg[rd] = dest; \
656: \
657: if(rd == 15) \
658: { \
659: arm_update_pc(); \
660: } \
661: } \
662:
663: #define flags_vars(src_a, src_b) \
664: u32 dest; \
665: const u32 _sa = src_a; \
666: const u32 _sb = src_b \
667:
668: #define arm_data_proc_logic_flags(expr, type) \
669: { \
670: arm_pc_offset(8); \
671: arm_data_proc_flags_##type(); \
672: u32 dest = expr; \
673: calculate_flags_logic(dest); \
674: arm_pc_offset(-4); \
675: reg[rd] = dest; \
676: arm_spsr_restore(); \
677: } \
678:
679: #define arm_data_proc_add_flags(src_a, src_b, type) \
680: { \
681: arm_pc_offset(8); \
682: arm_data_proc_##type(); \
683: flags_vars(src_a, src_b); \
684: dest = _sa + _sb; \
685: calculate_flags_add(dest, _sa, _sb); \
686: arm_pc_offset(-4); \
687: reg[rd] = dest; \
688: arm_spsr_restore(); \
689: }
690:
691: #define arm_data_proc_sub_flags(src_a, src_b, type) \
692: { \
693: arm_pc_offset(8); \
694: arm_data_proc_##type(); \
695: flags_vars(src_a, src_b); \
696: dest = _sa - _sb; \
697: calculate_flags_sub(dest, _sa, _sb); \
698: arm_pc_offset(-4); \
699: reg[rd] = dest; \
700: arm_spsr_restore(); \
701: } \
702:
703: #define arm_data_proc_test_logic(expr, type) \
704: { \
705: arm_pc_offset(8); \
706: arm_data_proc_flags_##type(); \
707: u32 dest = expr; \
708: calculate_flags_logic(dest); \
709: arm_pc_offset(-4); \
710: } \
711:
712: #define arm_data_proc_test_add(src_a, src_b, type) \
713: { \
714: arm_pc_offset(8); \
715: arm_data_proc_##type(); \
716: flags_vars(src_a, src_b); \
717: dest = _sa + _sb; \
718: calculate_flags_add(dest, _sa, _sb); \
719: arm_pc_offset(-4); \
720: } \
721:
722: #define arm_data_proc_test_sub(src_a, src_b, type) \
723: { \
724: arm_pc_offset(8); \
725: arm_data_proc_##type(); \
726: flags_vars(src_a, src_b); \
727: dest = _sa - _sb; \
728: calculate_flags_sub(dest, _sa, _sb); \
729: arm_pc_offset(-4); \
730: } \
731:
732: #define arm_multiply_flags_yes(_dest) \
733: calculate_z_flag(_dest); \
734: calculate_n_flag(_dest) \
735:
736: #define arm_multiply_flags_no(_dest) \
737:
738: #define arm_multiply_long_flags_yes(_dest_lo, _dest_hi) \
739: z_flag = ((_dest_lo) == 0) & ((_dest_hi) == 0); \
740: calculate_n_flag(_dest_hi) \
741:
742: #define arm_multiply_long_flags_no(_dest_lo, _dest_hi) \
743:
744: #define arm_multiply(add_op, flags) \
745: { \
746: u32 dest; \
747: arm_decode_multiply(); \
748: dest = (reg[rm] * reg[rs]) add_op; \
749: arm_multiply_flags_##flags(dest); \
750: reg[rd] = dest; \
751: arm_pc_offset(4); \
752: } \
753:
754: #define arm_multiply_long_addop(type) \
755: + ((type##64)((((type##64)reg[rdhi]) << 32) | reg[rdlo])) \
756:
757: #define arm_multiply_long(add_op, flags, type) \
758: { \
759: type##64 dest; \
760: u32 dest_lo; \
761: u32 dest_hi; \
762: arm_decode_multiply_long(); \
763: dest = ((type##64)((type##32)reg[rm]) * \
764: (type##64)((type##32)reg[rn])) add_op; \
765: dest_lo = (u32)dest; \
766: dest_hi = (u32)(dest >> 32); \
767: arm_multiply_long_flags_##flags(dest_lo, dest_hi); \
768: reg[rdlo] = dest_lo; \
769: reg[rdhi] = dest_hi; \
770: arm_pc_offset(4); \
771: } \
772:
773: #define arm_psr_read(dummy, psr_reg) \
774: collapse_flags(); \
775: reg[rd] = psr_reg \
776:
777: #define arm_psr_store_cpsr(source) \
778: reg[REG_CPSR] = ((source) & store_mask) | (reg[REG_CPSR] & (~store_mask)); \
779: extract_flags(); \
780: if(store_mask & 0xFF) \
781: { \
782: set_cpu_mode(cpu_modes[reg[REG_CPSR] & 0x1F]); \
783: check_for_interrupts(); \
784: } \
785:
786: #define arm_psr_store_spsr(source) \
787: u32 _psr = spsr[reg[CPU_MODE]]; \
788: spsr[reg[CPU_MODE]] = ((source) & store_mask) | (_psr & (~store_mask)) \
789:
790: #define arm_psr_store(source, psr_reg) \
791: const u32 store_mask = psr_masks[psr_field]; \
792: arm_psr_store_##psr_reg(source) \
793:
794: #define arm_psr_src_reg reg[rm]
795:
796: #define arm_psr_src_imm imm
797:
798: #define arm_psr(op_type, transfer_type, psr_reg) \
799: { \
800: arm_decode_psr_##op_type(); \
801: arm_pc_offset(4); \
802: arm_psr_##transfer_type(arm_psr_src_##op_type, psr_reg); \
803: } \
804:
805: #define arm_data_trans_reg() \
806: arm_decode_data_trans_reg(); \
807: calculate_reg_offset() \
808:
809: #define arm_data_trans_imm() \
810: arm_decode_data_trans_imm() \
811:
812: #define arm_data_trans_half_reg() \
813: arm_decode_half_trans_r() \
814:
815: #define arm_data_trans_half_imm() \
816: arm_decode_half_trans_of() \
817:
818: #define aligned_address_mask8 0xF0000000
819: #define aligned_address_mask16 0xF0000001
820: #define aligned_address_mask32 0xF0000003
821:
822: #define fast_read_memory(size, type, address, dest) \
823: { \
824: u8 *map; \
825: u32 _address = address; \
826: \
827: if(_address < 0x10000000) \
828: { \
829: memory_region_access_read_##type[_address >> 24]++; \
830: memory_reads_##type++; \
831: } \
832: if(((_address >> 24) == 0) && (pc >= 0x4000)) \
833: { \
834: dest = *((type *)((u8 *)&bios_read_protect + (_address & 0x03))); \
835: } \
836: else \
837: \
838: if(((_address & aligned_address_mask##size) == 0) && \
839: (map = memory_map_read[_address >> 15])) \
840: { \
841: dest = *((type *)((u8 *)map + (_address & 0x7FFF))); \
842: } \
843: else \
844: { \
845: dest = (type)read_memory##size(_address); \
846: } \
847: } \
848:
849: #define fast_read_memory_s16(address, dest) \
850: { \
851: u8 *map; \
852: u32 _address = address; \
853: \
854: if(_address < 0x10000000) \
855: { \
856: memory_region_access_read_s16[_address >> 24]++; \
857: memory_reads_s16++; \
858: } \
859: if(((_address & aligned_address_mask16) == 0) && \
860: (map = memory_map_read[_address >> 15])) \
861: { \
862: dest = *((s16 *)((u8 *)map + (_address & 0x7FFF))); \
863: } \
864: else \
865: { \
866: dest = (s16)read_memory16_signed(_address); \
867: } \
868: } \
869:
870:
871: #define fast_write_memory(size, type, address, value) \
872: { \
873: u8 *map; \
874: u32 _address = (address) & ~(aligned_address_mask##size & 0x03); \
875: if(_address < 0x10000000) \
876: { \
877: memory_region_access_write_##type[_address >> 24]++; \
878: memory_writes_##type++; \
879: } \
880: \
881: if(((_address & aligned_address_mask##size) == 0) && \
882: (map = memory_map_write[_address >> 15])) \
883: { \
884: *((type *)((u8 *)map + (_address & 0x7FFF))) = value; \
885: } \
886: else \
887: { \
888: cpu_alert = write_memory##size(_address, value); \
889: if(cpu_alert) \
890: goto alert; \
891: } \
892: } \
893:
894: #define load_aligned32(address, dest) \
895: { \
896: u8 *map = memory_map_read[(address) >> 15]; \
897: if(address < 0x10000000) \
898: { \
899: memory_region_access_read_u32[(address) >> 24]++; \
900: memory_reads_u32++; \
901: } \
902: if(map) \
903: { \
904: dest = ADDRESS32(map, (address) & 0x7FFF); \
905: } \
906: else \
907: { \
908: dest = read_memory32(address); \
909: } \
910: } \
911:
912: #define store_aligned32(address, value) \
913: { \
914: u8 *map = memory_map_write[(address) >> 15]; \
915: if(address < 0x10000000) \
916: { \
917: memory_region_access_write_u32[(address) >> 24]++; \
918: memory_writes_u32++; \
919: } \
920: if(map) \
921: { \
922: ADDRESS32(map, (address) & 0x7FFF) = value; \
923: } \
924: else \
925: { \
926: cpu_alert = write_memory32(address, value); \
927: if(cpu_alert) \
928: goto alert; \
929: } \
930: } \
931:
932: #define load_memory_u8(address, dest) \
933: fast_read_memory(8, u8, address, dest) \
934:
935: #define load_memory_u16(address, dest) \
936: fast_read_memory(16, u16, address, dest) \
937:
938: #define load_memory_u32(address, dest) \
939: fast_read_memory(32, u32, address, dest) \
940:
941: #define load_memory_s8(address, dest) \
942: fast_read_memory(8, s8, address, dest) \
943:
944: #define load_memory_s16(address, dest) \
945: fast_read_memory_s16(address, dest) \
946:
947: #define store_memory_u8(address, value) \
948: fast_write_memory(8, u8, address, value) \
949:
950: #define store_memory_u16(address, value) \
951: fast_write_memory(16, u16, address, value) \
952:
953: #define store_memory_u32(address, value) \
954: fast_write_memory(32, u32, address, value) \
955:
956: #define no_op \
957:
958: #define arm_access_memory_writeback_yes(off_op) \
959: reg[rn] = address off_op \
960:
961: #define arm_access_memory_writeback_no(off_op) \
962:
963: #define arm_access_memory_pc_preadjust_load() \
964:
965: #define arm_access_memory_pc_preadjust_store() \
966: u32 reg_op = reg[rd]; \
967: if(rd == 15) \
968: reg_op += 4 \
969:
970: #define arm_access_memory_pc_postadjust_load() \
971: arm_update_pc() \
972:
973: #define arm_access_memory_pc_postadjust_store() \
974:
975: #define load_reg_op reg[rd] \
976:
977: #define store_reg_op reg_op \
978:
979: #define arm_access_memory(access_type, off_op, off_type, mem_type, \
980: wb, wb_off_op) \
981: { \
982: arm_pc_offset(8); \
983: arm_data_trans_##off_type(); \
984: u32 address = reg[rn] off_op; \
985: arm_access_memory_pc_preadjust_##access_type(); \
986: \
987: arm_pc_offset(-4); \
988: arm_access_memory_writeback_##wb(wb_off_op); \
989: access_type##_memory_##mem_type(address, access_type##_reg_op); \
990: arm_access_memory_pc_postadjust_##access_type(); \
991: } \
992:
993: #define word_bit_count(word) \
994: (bit_count[(word) >> 8] + bit_count[word & 0xFF]) \
995:
996: #define sprint_no(access_type, pre_op, post_op, wb) \
997:
998: #define sprint_yes(access_type, pre_op, post_op, wb) \
999: printf("sbit on %s %s %s %s\n", #access_type, #pre_op, #post_op, #wb) \
1000:
1001: #define arm_block_writeback_load() \
1002: if(!((reg_list >> rn) & 0x01)) \
1003: { \
1004: reg[rn] = address; \
1005: } \
1006:
1007: #define arm_block_writeback_store() \
1008: reg[rn] = address \
1009:
1010: #define arm_block_writeback_yes(access_type) \
1011: arm_block_writeback_##access_type() \
1012:
1013: #define arm_block_writeback_no(access_type) \
1014:
1015: #define load_block_memory(address, dest) \
1016: dest = ADDRESS32(address_region, ((address) + offset) & 0x7FFF) \
1017:
1018: #define store_block_memory(address, dest) \
1019: ADDRESS32(address_region, ((address) + offset) & 0x7FFF) = dest \
1020:
1021: #define arm_block_memory_offset_down_a() \
1022: (base - ((word_bit_count(reg_list) * 4) - 4)) \
1023:
1024: #define arm_block_memory_offset_down_b() \
1025: (base - (word_bit_count(reg_list) * 4)) \
1026:
1027: #define arm_block_memory_offset_no() \
1028: (base) \
1029:
1030: #define arm_block_memory_offset_up() \
1031: (base + 4) \
1032:
1033: #define arm_block_memory_writeback_down() \
1034: reg[rn] = base - (word_bit_count(reg_list) * 4) \
1035:
1036: #define arm_block_memory_writeback_up() \
1037: reg[rn] = base + (word_bit_count(reg_list) * 4) \
1038:
1039: #define arm_block_memory_writeback_no() \
1040:
1041: #define arm_block_memory_load_pc() \
1042: load_aligned32(address, pc); \
1043: reg[REG_PC] = pc \
1044:
1045: #define arm_block_memory_store_pc() \
1046: store_aligned32(address, pc + 4) \
1047:
1048: #define arm_block_memory(access_type, offset_type, writeback_type, s_bit) \
1049: { \
1050: arm_decode_block_trans(); \
1051: u32 base = reg[rn]; \
1052: u32 address = arm_block_memory_offset_##offset_type() & 0xFFFFFFFC; \
1053: u32 i; \
1054: \
1055: arm_block_memory_writeback_##writeback_type(); \
1056: \
1057: for(i = 0; i < 15; i++) \
1058: { \
1059: if((reg_list >> i) & 0x01) \
1060: { \
1061: access_type##_aligned32(address, reg[i]); \
1062: address += 4; \
1063: } \
1064: } \
1065: \
1066: arm_pc_offset(4); \
1067: if(reg_list & 0x8000) \
1068: { \
1069: arm_block_memory_##access_type##_pc(); \
1070: } \
1071: } \
1072:
1073: #define arm_swap(type) \
1074: { \
1075: arm_decode_swap(); \
1076: u32 temp; \
1077: load_memory_##type(reg[rn], temp); \
1078: store_memory_##type(reg[rn], reg[rm]); \
1079: reg[rd] = temp; \
1080: arm_pc_offset(4); \
1081: } \
1082:
1083: #define arm_next_instruction() \
1084: { \
1085: arm_pc_offset(4); \
1086: goto skip_instruction; \
1087: } \
1088:
1089: #define thumb_update_pc() \
1090: pc = reg[REG_PC] \
1091:
1092: #define thumb_pc_offset(val) \
1093: pc += val; \
1094: reg[REG_PC] = pc \
1095:
1096: #define thumb_pc_offset_update(val) \
1097: pc += val; \
1098: reg[REG_PC] = pc \
1099:
1100: #define thumb_pc_offset_update_direct(val) \
1101: pc = val; \
1102: reg[REG_PC] = pc \
1103:
1104: #define thumb_decode_shift() \
1105: u32 imm = (opcode >> 6) & 0x1F; \
1106: u32 rs = (opcode >> 3) & 0x07; \
1107: u32 rd = opcode & 0x07 \
1108:
1109: #define thumb_decode_add_sub() \
1110: u32 rn = (opcode >> 6) & 0x07; \
1111: u32 rs = (opcode >> 3) & 0x07; \
1112: u32 rd = opcode & 0x07 \
1113:
1114: #define thumb_decode_add_sub_imm() \
1115: u32 imm = (opcode >> 6) & 0x07; \
1116: u32 rs = (opcode >> 3) & 0x07; \
1117: u32 rd = opcode & 0x07 \
1118:
1119: #define thumb_decode_imm() \
1120: u32 imm = opcode & 0xFF \
1121:
1122: #define thumb_decode_alu_op() \
1123: u32 rs = (opcode >> 3) & 0x07; \
1124: u32 rd = opcode & 0x07 \
1125:
1126: #define thumb_decode_hireg_op() \
1127: u32 rs = (opcode >> 3) & 0x0F; \
1128: u32 rd = ((opcode >> 4) & 0x08) | (opcode & 0x07) \
1129:
1130: #define thumb_decode_mem_reg() \
1131: u32 ro = (opcode >> 6) & 0x07; \
1132: u32 rb = (opcode >> 3) & 0x07; \
1133: u32 rd = opcode & 0x07 \
1134:
1135: #define thumb_decode_mem_imm() \
1136: u32 imm = (opcode >> 6) & 0x1F; \
1137: u32 rb = (opcode >> 3) & 0x07; \
1138: u32 rd = opcode & 0x07 \
1139:
1140: #define thumb_decode_add_sp() \
1141: u32 imm = opcode & 0x7F \
1142:
1143: #define thumb_decode_rlist() \
1144: u32 reg_list = opcode & 0xFF \
1145:
1146: #define thumb_decode_branch_cond() \
1147: s32 offset = (s8)(opcode & 0xFF) \
1148:
1149: #define thumb_decode_swi() \
1150: u32 comment = opcode & 0xFF \
1151:
1152: #define thumb_decode_branch() \
1153: u32 offset = opcode & 0x07FF \
1154:
1155: // Types: add_sub, add_sub_imm, alu_op, imm
1156: // Affects N/Z/C/V flags
1157:
1158: #define thumb_add(type, dest_reg, src_a, src_b) \
1159: { \
1160: thumb_decode_##type(); \
1161: const u32 _sa = src_a; \
1162: const u32 _sb = src_b; \
1163: u32 dest = _sa + _sb; \
1164: calculate_flags_add(dest, src_a, src_b); \
1165: reg[dest_reg] = dest; \
1166: thumb_pc_offset(2); \
1167: } \
1168:
1169: #define thumb_add_noflags(type, dest_reg, src_a, src_b) \
1170: { \
1171: thumb_decode_##type(); \
1172: u32 dest = (src_a) + (src_b); \
1173: reg[dest_reg] = dest; \
1174: thumb_pc_offset(2); \
1175: } \
1176:
1177: #define thumb_sub(type, dest_reg, src_a, src_b) \
1178: { \
1179: thumb_decode_##type(); \
1180: const u32 _sa = src_a; \
1181: const u32 _sb = src_b; \
1182: u32 dest = _sa - _sb; \
1183: calculate_flags_sub(dest, src_a, src_b); \
1184: reg[dest_reg] = dest; \
1185: thumb_pc_offset(2); \
1186: } \
1187:
1188: #define thumb_subc(type, dest_reg, src_a, src_b, carry) \
1189: { \
1190: thumb_decode_##type(); \
1191: const u32 _sa = src_a; \
1192: const u32 _sb = src_b; \
1193: u32 dest = _sa - _sb - (c_flag ^ 1); \
1194: calculate_flags_sub(dest, src_a, src_b); \
1195: reg[dest_reg] = dest; \
1196: thumb_pc_offset(2); \
1197: } \
1198:
1199: // Affects N/Z flags
1200:
1201: #define thumb_logic(type, dest_reg, expr) \
1202: { \
1203: thumb_decode_##type(); \
1204: u32 dest = expr; \
1205: calculate_flags_logic(dest); \
1206: reg[dest_reg] = dest; \
1207: thumb_pc_offset(2); \
1208: } \
1209:
1210: // Decode types: shift, alu_op
1211: // Operation types: lsl, lsr, asr, ror
1212: // Affects N/Z/C flags
1213:
1214: #define thumb_shift_lsl_reg() \
1215: u32 shift = reg[rs]; \
1216: u32 dest = reg[rd]; \
1217: if(shift != 0) \
1218: { \
1219: if(shift > 31) \
1220: { \
1221: if(shift == 32) \
1222: c_flag = dest & 0x01; \
1223: else \
1224: c_flag = 0; \
1225: dest = 0; \
1226: } \
1227: else \
1228: { \
1229: c_flag = (dest >> (32 - shift)) & 0x01; \
1230: dest <<= shift; \
1231: } \
1232: } \
1233:
1234: #define thumb_shift_lsr_reg() \
1235: u32 shift = reg[rs]; \
1236: u32 dest = reg[rd]; \
1237: if(shift != 0) \
1238: { \
1239: if(shift > 31) \
1240: { \
1241: if(shift == 32) \
1242: c_flag = dest >> 31; \
1243: else \
1244: c_flag = 0; \
1245: dest = 0; \
1246: } \
1247: else \
1248: { \
1249: c_flag = (dest >> (shift - 1)) & 0x01; \
1250: dest >>= shift; \
1251: } \
1252: } \
1253:
1254: #define thumb_shift_asr_reg() \
1255: u32 shift = reg[rs]; \
1256: u32 dest = reg[rd]; \
1257: if(shift != 0) \
1258: { \
1259: if(shift > 31) \
1260: { \
1261: dest = (s32)dest >> 31; \
1262: c_flag = dest & 0x01; \
1263: } \
1264: else \
1265: { \
1266: c_flag = (dest >> (shift - 1)) & 0x01; \
1267: dest = (s32)dest >> shift; \
1268: } \
1269: } \
1270:
1271: #define thumb_shift_ror_reg() \
1272: u32 shift = reg[rs]; \
1273: u32 dest = reg[rd]; \
1274: if(shift != 0) \
1275: { \
1276: c_flag = (dest >> (shift - 1)) & 0x01; \
1277: ROR(dest, dest, shift); \
1278: } \
1279:
1280: #define thumb_shift_lsl_imm() \
1281: u32 dest = reg[rs]; \
1282: if(imm != 0) \
1283: { \
1284: c_flag = (dest >> (32 - imm)) & 0x01; \
1285: dest <<= imm; \
1286: } \
1287:
1288: #define thumb_shift_lsr_imm() \
1289: u32 dest; \
1290: if(imm == 0) \
1291: { \
1292: dest = 0; \
1293: c_flag = reg[rs] >> 31; \
1294: } \
1295: else \
1296: { \
1297: dest = reg[rs]; \
1298: c_flag = (dest >> (imm - 1)) & 0x01; \
1299: dest >>= imm; \
1300: } \
1301:
1302: #define thumb_shift_asr_imm() \
1303: u32 dest; \
1304: if(imm == 0) \
1305: { \
1306: dest = (s32)reg[rs] >> 31; \
1307: c_flag = dest & 0x01; \
1308: } \
1309: else \
1310: { \
1311: dest = reg[rs]; \
1312: c_flag = (dest >> (imm - 1)) & 0x01; \
1313: dest = (s32)dest >> imm; \
1314: } \
1315:
1316: #define thumb_shift_ror_imm() \
1317: u32 dest = reg[rs]; \
1318: if(imm == 0) \
1319: { \
1320: u32 old_c_flag = c_flag; \
1321: c_flag = dest & 0x01; \
1322: dest = (dest >> 1) | (old_c_flag << 31); \
1323: } \
1324: else \
1325: { \
1326: c_flag = (dest >> (imm - 1)) & 0x01; \
1327: ROR(dest, dest, imm); \
1328: } \
1329:
1330: #define thumb_shift(decode_type, op_type, value_type) \
1331: { \
1332: thumb_decode_##decode_type(); \
1333: thumb_shift_##op_type##_##value_type(); \
1334: calculate_flags_logic(dest); \
1335: reg[rd] = dest; \
1336: thumb_pc_offset(2); \
1337: } \
1338:
1339: #define thumb_test_add(type, src_a, src_b) \
1340: { \
1341: thumb_decode_##type(); \
1342: const u32 _sa = src_a; \
1343: const u32 _sb = src_b; \
1344: u32 dest = _sa + _sb; \
1345: calculate_flags_add(dest, src_a, src_b); \
1346: thumb_pc_offset(2); \
1347: } \
1348:
1349: #define thumb_test_sub(type, src_a, src_b) \
1350: { \
1351: thumb_decode_##type(); \
1352: const u32 _sa = src_a; \
1353: const u32 _sb = src_b; \
1354: u32 dest = _sa - _sb; \
1355: calculate_flags_sub(dest, src_a, src_b); \
1356: thumb_pc_offset(2); \
1357: } \
1358:
1359: #define thumb_test_logic(type, expr) \
1360: { \
1361: thumb_decode_##type(); \
1362: u32 dest = expr; \
1363: calculate_flags_logic(dest); \
1364: thumb_pc_offset(2); \
1365: }
1366:
1367: #define thumb_hireg_op(expr) \
1368: { \
1369: thumb_pc_offset(4); \
1370: thumb_decode_hireg_op(); \
1371: u32 dest = expr; \
1372: thumb_pc_offset(-2); \
1373: if(rd == 15) \
1374: { \
1375: reg[REG_PC] = dest & ~0x01; \
1376: thumb_update_pc(); \
1377: } \
1378: else \
1379: { \
1380: reg[rd] = dest; \
1381: } \
1382: } \
1383:
1384: // Operation types: imm, mem_reg, mem_imm
1385:
1386: #define thumb_access_memory(access_type, op_type, address, reg_op, \
1387: mem_type) \
1388: { \
1389: thumb_decode_##op_type(); \
1390: access_type##_memory_##mem_type(address, reg_op); \
1391: thumb_pc_offset(2); \
1392: } \
1393:
1394: #define thumb_block_address_preadjust_no_op() \
1395:
1396: #define thumb_block_address_preadjust_up() \
1397: address += bit_count[reg_list] * 4 \
1398:
1399: #define thumb_block_address_preadjust_down() \
1400: address -= bit_count[reg_list] * 4 \
1401:
1402: #define thumb_block_address_preadjust_push_lr() \
1403: address -= (bit_count[reg_list] + 1) * 4 \
1404:
1405: #define thumb_block_address_postadjust_no_op() \
1406:
1407: #define thumb_block_address_postadjust_up() \
1408: address += offset \
1409:
1410: #define thumb_block_address_postadjust_down() \
1411: address -= offset \
1412:
1413: #define thumb_block_address_postadjust_pop_pc() \
1414: load_memory_u32(address + offset, pc); \
1415: pc &= ~0x01; \
1416: reg[REG_PC] = pc; \
1417: address += offset + 4 \
1418:
1419: #define thumb_block_address_postadjust_push_lr() \
1420: store_memory_u32(address + offset, reg[REG_LR]) \
1421:
1422: #define thumb_block_memory_wb_load(base_reg) \
1423: if(!((reg_list >> base_reg) & 0x01)) \
1424: { \
1425: reg[base_reg] = address; \
1426: } \
1427:
1428: #define thumb_block_memory_wb_store(base_reg) \
1429: reg[base_reg] = address \
1430:
1431: #define thumb_block_memory(access_type, pre_op, post_op, base_reg) \
1432: { \
1433: u32 i; \
1434: u32 offset = 0; \
1435: thumb_decode_rlist(); \
1436: u32 address = reg[base_reg] & ~0x03; \
1437: thumb_block_address_preadjust_##pre_op(); \
1438: \
1439: for(i = 0; i < 8; i++) \
1440: { \
1441: if((reg_list >> i) & 1) \
1442: { \
1443: access_type##_aligned32(address + offset, reg[i]); \
1444: offset += 4; \
1445: } \
1446: } \
1447: \
1448: thumb_pc_offset(2); \
1449: \
1450: thumb_block_address_postadjust_##post_op(); \
1451: thumb_block_memory_wb_##access_type(base_reg); \
1452: \
1453: } \
1454:
1455: #define thumb_conditional_branch(condition) \
1456: { \
1457: thumb_decode_branch_cond(); \
1458: if(condition) \
1459: { \
1460: thumb_pc_offset((offset * 2) + 4); \
1461: } \
1462: else \
1463: { \
1464: thumb_pc_offset(2); \
1465: } \
1466: } \
1467:
1468: #define execute_arm_instruction() \
1469: check_pc_region(); \
1470: pc &= ~0x03; \
1471: opcode = ADDRESS32(pc_address_block, (pc & 0x7FFF)); \
1472: condition = opcode >> 28; \
1473: \
1474: switch(condition) \
1475: { \
1476: case 0x0: \
1477: /* EQ */ \
1478: if(!z_flag) \
1479: arm_next_instruction(); \
1480: break; \
1481: \
1482: case 0x1: \
1483: /* NE */ \
1484: if(z_flag) \
1485: arm_next_instruction(); \
1486: break; \
1487: \
1488: case 0x2: \
1489: /* CS */ \
1490: if(!c_flag) \
1491: arm_next_instruction(); \
1492: break; \
1493: \
1494: case 0x3: \
1495: /* CC */ \
1496: if(c_flag) \
1497: arm_next_instruction(); \
1498: break; \
1499: \
1500: case 0x4: \
1501: /* MI */ \
1502: if(!n_flag) \
1503: arm_next_instruction(); \
1504: break; \
1505: \
1506: case 0x5: \
1507: /* PL */ \
1508: if(n_flag) \
1509: arm_next_instruction(); \
1510: break; \
1511: \
1512: case 0x6: \
1513: /* VS */ \
1514: if(!v_flag) \
1515: arm_next_instruction(); \
1516: break; \
1517: \
1518: case 0x7: \
1519: /* VC */ \
1520: if(v_flag) \
1521: arm_next_instruction(); \
1522: break; \
1523: \
1524: case 0x8: \
1525: /* HI */ \
1526: if((c_flag == 0) | z_flag) \
1527: arm_next_instruction(); \
1528: break; \
1529: \
1530: case 0x9: \
1531: /* LS */ \
1532: if(c_flag & (z_flag ^ 1)) \
1533: arm_next_instruction(); \
1534: break; \
1535: \
1536: case 0xA: \
1537: /* GE */ \
1538: if(n_flag != v_flag) \
1539: arm_next_instruction(); \
1540: break; \
1541: \
1542: case 0xB: \
1543: /* LT */ \
1544: if(n_flag == v_flag) \
1545: arm_next_instruction(); \
1546: break; \
1547: \
1548: case 0xC: \
1549: /* GT */ \
1550: if(z_flag | (n_flag != v_flag)) \
1551: arm_next_instruction(); \
1552: break; \
1553: \
1554: case 0xD: \
1555: /* LE */ \
1556: if((z_flag == 0) & (n_flag == v_flag)) \
1557: arm_next_instruction(); \
1558: break; \
1559: \
1560: case 0xE: \
1561: /* AL */ \
1562: break; \
1563: \
1564: case 0xF: \
1565: /* Reserved - treat as "never" */ \
1566: quit(); \
1567: arm_next_instruction(); \
1568: break; \
1569: } \
1570: \
1571: switch((opcode >> 20) & 0xFF) \
1572: { \
1573: case 0x00: \
1574: if((opcode & 0x90) == 0x90) \
1575: { \
1576: if(opcode & 0x20) \
1577: { \
1578: /* STRH rd, [rn], -rm */ \
1579: arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); \
1580: } \
1581: else \
1582: { \
1583: /* MUL rd, rm, rs */ \
1584: arm_multiply(no_op, no); \
1585: } \
1586: } \
1587: else \
1588: { \
1589: /* AND rd, rn, reg_op */ \
1590: arm_data_proc(reg[rn] & reg_sh, reg); \
1591: } \
1592: break; \
1593: \
1594: case 0x01: \
1595: if((opcode & 0x90) == 0x90) \
1596: { \
1597: switch((opcode >> 5) & 0x03) \
1598: { \
1599: case 0: \
1600: /* MULS rd, rm, rs */ \
1601: arm_multiply(no_op, yes); \
1602: break; \
1603: \
1604: case 1: \
1605: /* LDRH rd, [rn], -rm */ \
1606: arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); \
1607: break; \
1608: \
1609: case 2: \
1610: /* LDRSB rd, [rn], -rm */ \
1611: arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); \
1612: break; \
1613: \
1614: case 3: \
1615: /* LDRSH rd, [rn], -rm */ \
1616: arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); \
1617: break; \
1618: } \
1619: } \
1620: else \
1621: { \
1622: /* ANDS rd, rn, reg_op */ \
1623: arm_data_proc_logic_flags(reg[rn] & reg_sh, reg); \
1624: } \
1625: break; \
1626: \
1627: case 0x02: \
1628: if((opcode & 0x90) == 0x90) \
1629: { \
1630: if(opcode & 0x20) \
1631: { \
1632: /* STRH rd, [rn], -rm */ \
1633: arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); \
1634: } \
1635: else \
1636: { \
1637: /* MLA rd, rm, rs, rn */ \
1638: arm_multiply(+ reg[rn], no); \
1639: } \
1640: } \
1641: else \
1642: { \
1643: /* EOR rd, rn, reg_op */ \
1644: arm_data_proc(reg[rn] ^ reg_sh, reg); \
1645: } \
1646: break; \
1647: \
1648: case 0x03: \
1649: if((opcode & 0x90) == 0x90) \
1650: { \
1651: switch((opcode >> 5) & 0x03) \
1652: { \
1653: case 0: \
1654: /* MLAS rd, rm, rs, rn */ \
1655: arm_multiply(+ reg[rn], yes); \
1656: break; \
1657: \
1658: case 1: \
1659: /* LDRH rd, [rn], -rm */ \
1660: arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); \
1661: break; \
1662: \
1663: case 2: \
1664: /* LDRSB rd, [rn], -rm */ \
1665: arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); \
1666: break; \
1667: \
1668: case 3: \
1669: /* LDRSH rd, [rn], -rm */ \
1670: arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); \
1671: break; \
1672: } \
1673: } \
1674: else \
1675: { \
1676: /* EORS rd, rn, reg_op */ \
1677: arm_data_proc_logic_flags(reg[rn] ^ reg_sh, reg); \
1678: } \
1679: break; \
1680: \
1681: case 0x04: \
1682: if((opcode & 0x90) == 0x90) \
1683: { \
1684: /* STRH rd, [rn], -imm */ \
1685: arm_access_memory(store, no_op, half_imm, u16, yes, - offset); \
1686: } \
1687: else \
1688: { \
1689: /* SUB rd, rn, reg_op */ \
1690: arm_data_proc(reg[rn] - reg_sh, reg); \
1691: } \
1692: break; \
1693: \
1694: case 0x05: \
1695: if((opcode & 0x90) == 0x90) \
1696: { \
1697: switch((opcode >> 5) & 0x03) \
1698: { \
1699: case 1: \
1700: /* LDRH rd, [rn], -imm */ \
1701: arm_access_memory(load, no_op, half_imm, u16, yes, - offset); \
1702: break; \
1703: \
1704: case 2: \
1705: /* LDRSB rd, [rn], -imm */ \
1706: arm_access_memory(load, no_op, half_imm, s8, yes, - offset); \
1707: break; \
1708: \
1709: case 3: \
1710: /* LDRSH rd, [rn], -imm */ \
1711: arm_access_memory(load, no_op, half_imm, s16, yes, - offset); \
1712: break; \
1713: } \
1714: } \
1715: else \
1716: { \
1717: /* SUBS rd, rn, reg_op */ \
1718: arm_data_proc_sub_flags(reg[rn], reg_sh, reg); \
1719: } \
1720: break; \
1721: \
1722: case 0x06: \
1723: if((opcode & 0x90) == 0x90) \
1724: { \
1725: /* STRH rd, [rn], -imm */ \
1726: arm_access_memory(store, no_op, half_imm, u16, yes, - offset); \
1727: } \
1728: else \
1729: { \
1730: /* RSB rd, rn, reg_op */ \
1731: arm_data_proc(reg_sh - reg[rn], reg); \
1732: } \
1733: break; \
1734: \
1735: case 0x07: \
1736: if((opcode & 0x90) == 0x90) \
1737: { \
1738: switch((opcode >> 5) & 0x03) \
1739: { \
1740: case 1: \
1741: /* LDRH rd, [rn], -imm */ \
1742: arm_access_memory(load, no_op, half_imm, u16, yes, - offset); \
1743: break; \
1744: \
1745: case 2: \
1746: /* LDRSB rd, [rn], -imm */ \
1747: arm_access_memory(load, no_op, half_imm, s8, yes, - offset); \
1748: break; \
1749: \
1750: case 3: \
1751: /* LDRSH rd, [rn], -imm */ \
1752: arm_access_memory(load, no_op, half_imm, s16, yes, - offset); \
1753: break; \
1754: } \
1755: } \
1756: else \
1757: { \
1758: /* RSBS rd, rn, reg_op */ \
1759: arm_data_proc_sub_flags(reg_sh, reg[rn], reg); \
1760: } \
1761: break; \
1762: \
1763: case 0x08: \
1764: if((opcode & 0x90) == 0x90) \
1765: { \
1766: if(opcode & 0x20) \
1767: { \
1768: /* STRH rd, [rn], +rm */ \
1769: arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); \
1770: } \
1771: else \
1772: { \
1773: /* UMULL rd, rm, rs */ \
1774: arm_multiply_long(no_op, no, u); \
1775: } \
1776: } \
1777: else \
1778: { \
1779: /* ADD rd, rn, reg_op */ \
1780: arm_data_proc(reg[rn] + reg_sh, reg); \
1781: } \
1782: break; \
1783: \
1784: case 0x09: \
1785: if((opcode & 0x90) == 0x90) \
1786: { \
1787: switch((opcode >> 5) & 0x03) \
1788: { \
1789: case 0: \
1790: /* UMULLS rdlo, rdhi, rm, rs */ \
1791: arm_multiply_long(no_op, yes, u); \
1792: break; \
1793: \
1794: case 1: \
1795: /* LDRH rd, [rn], +rm */ \
1796: arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); \
1797: break; \
1798: \
1799: case 2: \
1800: /* LDRSB rd, [rn], +rm */ \
1801: arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); \
1802: break; \
1803: \
1804: case 3: \
1805: /* LDRSH rd, [rn], +rm */ \
1806: arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); \
1807: break; \
1808: } \
1809: } \
1810: else \
1811: { \
1812: /* ADDS rd, rn, reg_op */ \
1813: arm_data_proc_add_flags(reg[rn], reg_sh, reg); \
1814: } \
1815: break; \
1816: \
1817: case 0x0A: \
1818: if((opcode & 0x90) == 0x90) \
1819: { \
1820: if(opcode & 0x20) \
1821: { \
1822: /* STRH rd, [rn], +rm */ \
1823: arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); \
1824: } \
1825: else \
1826: { \
1827: /* UMLAL rd, rm, rs */ \
1828: arm_multiply_long(arm_multiply_long_addop(u), no, u); \
1829: } \
1830: } \
1831: else \
1832: { \
1833: /* ADC rd, rn, reg_op */ \
1834: arm_data_proc(reg[rn] + reg_sh + c_flag, reg); \
1835: } \
1836: break; \
1837: \
1838: case 0x0B: \
1839: if((opcode & 0x90) == 0x90) \
1840: { \
1841: switch((opcode >> 5) & 0x03) \
1842: { \
1843: case 0: \
1844: /* UMLALS rdlo, rdhi, rm, rs */ \
1845: arm_multiply_long(arm_multiply_long_addop(u), yes, u); \
1846: break; \
1847: \
1848: case 1: \
1849: /* LDRH rd, [rn], +rm */ \
1850: arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); \
1851: break; \
1852: \
1853: case 2: \
1854: /* LDRSB rd, [rn], +rm */ \
1855: arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); \
1856: break; \
1857: \
1858: case 3: \
1859: /* LDRSH rd, [rn], +rm */ \
1860: arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); \
1861: break; \
1862: } \
1863: } \
1864: else \
1865: { \
1866: /* ADCS rd, rn, reg_op */ \
1867: arm_data_proc_add_flags(reg[rn], reg_sh + c_flag, reg); \
1868: } \
1869: break; \
1870: \
1871: case 0x0C: \
1872: if((opcode & 0x90) == 0x90) \
1873: { \
1874: if(opcode & 0x20) \
1875: { \
1876: /* STRH rd, [rn], +imm */ \
1877: arm_access_memory(store, no_op, half_imm, u16, yes, + offset); \
1878: } \
1879: else \
1880: { \
1881: /* SMULL rd, rm, rs */ \
1882: arm_multiply_long(no_op, no, s); \
1883: } \
1884: } \
1885: else \
1886: { \
1887: /* SBC rd, rn, reg_op */ \
1888: arm_data_proc(reg[rn] - (reg_sh + (c_flag ^ 1)), reg); \
1889: } \
1890: break; \
1891: \
1892: case 0x0D: \
1893: if((opcode & 0x90) == 0x90) \
1894: { \
1895: switch((opcode >> 5) & 0x03) \
1896: { \
1897: case 0: \
1898: /* SMULLS rdlo, rdhi, rm, rs */ \
1899: arm_multiply_long(no_op, yes, s); \
1900: break; \
1901: \
1902: case 1: \
1903: /* LDRH rd, [rn], +imm */ \
1904: arm_access_memory(load, no_op, half_imm, u16, yes, + offset); \
1905: break; \
1906: \
1907: case 2: \
1908: /* LDRSB rd, [rn], +imm */ \
1909: arm_access_memory(load, no_op, half_imm, s8, yes, + offset); \
1910: break; \
1911: \
1912: case 3: \
1913: /* LDRSH rd, [rn], +imm */ \
1914: arm_access_memory(load, no_op, half_imm, s16, yes, + offset); \
1915: break; \
1916: } \
1917: } \
1918: else \
1919: { \
1920: /* SBCS rd, rn, reg_op */ \
1921: arm_data_proc_sub_flags(reg[rn], (reg_sh + (c_flag ^ 1)), reg); \
1922: } \
1923: break; \
1924: \
1925: case 0x0E: \
1926: if((opcode & 0x90) == 0x90) \
1927: { \
1928: if(opcode & 0x20) \
1929: { \
1930: /* STRH rd, [rn], +imm */ \
1931: arm_access_memory(store, no_op, half_imm, u16, yes, + offset); \
1932: } \
1933: else \
1934: { \
1935: /* SMLAL rd, rm, rs */ \
1936: arm_multiply_long(arm_multiply_long_addop(s), no, s); \
1937: } \
1938: } \
1939: else \
1940: { \
1941: /* RSC rd, rn, reg_op */ \
1942: arm_data_proc(reg_sh - (reg[rn] + (c_flag ^ 1)), reg); \
1943: } \
1944: break; \
1945: \
1946: case 0x0F: \
1947: if((opcode & 0x90) == 0x90) \
1948: { \
1949: switch((opcode >> 5) & 0x03) \
1950: { \
1951: case 0: \
1952: /* SMLALS rdlo, rdhi, rm, rs */ \
1953: arm_multiply_long(arm_multiply_long_addop(s), yes, s); \
1954: break; \
1955: \
1956: case 1: \
1957: /* LDRH rd, [rn], +imm */ \
1958: arm_access_memory(load, no_op, half_imm, u16, yes, + offset); \
1959: break; \
1960: \
1961: case 2: \
1962: /* LDRSB rd, [rn], +imm */ \
1963: arm_access_memory(load, no_op, half_imm, s8, yes, + offset); \
1964: break; \
1965: \
1966: case 3: \
1967: /* LDRSH rd, [rn], +imm */ \
1968: arm_access_memory(load, no_op, half_imm, s16, yes, + offset); \
1969: break; \
1970: } \
1971: } \
1972: else \
1973: { \
1974: /* RSCS rd, rn, reg_op */ \
1975: arm_data_proc_sub_flags(reg_sh, reg[rn] + (c_flag ^ 1), reg); \
1976: } \
1977: break; \
1978: \
1979: case 0x10: \
1980: if((opcode & 0x90) == 0x90) \
1981: { \
1982: if(opcode & 0x20) \
1983: { \
1984: /* STRH rd, [rn - rm] */ \
1985: arm_access_memory(store, - reg[rm], half_reg, u16, no, no_op); \
1986: } \
1987: else \
1988: { \
1989: /* SWP rd, rm, [rn] */ \
1990: arm_swap(u32); \
1991: } \
1992: } \
1993: else \
1994: { \
1995: /* MRS rd, cpsr */ \
1996: arm_psr(reg, read, reg[REG_CPSR]); \
1997: } \
1998: break; \
1999: \
2000: case 0x11: \
2001: if((opcode & 0x90) == 0x90) \
2002: { \
2003: switch((opcode >> 5) & 0x03) \
2004: { \
2005: case 1: \
2006: /* LDRH rd, [rn - rm] */ \
2007: arm_access_memory(load, - reg[rm], half_reg, u16, no, no_op); \
2008: break; \
2009: \
2010: case 2: \
2011: /* LDRSB rd, [rn - rm] */ \
2012: arm_access_memory(load, - reg[rm], half_reg, s8, no, no_op); \
2013: break; \
2014: \
2015: case 3: \
2016: /* LDRSH rd, [rn - rm] */ \
2017: arm_access_memory(load, - reg[rm], half_reg, s16, no, no_op); \
2018: break; \
2019: } \
2020: } \
2021: else \
2022: { \
2023: /* TST rd, rn, reg_op */ \
2024: arm_data_proc_test_logic(reg[rn] & reg_sh, reg); \
2025: } \
2026: break; \
2027: \
2028: case 0x12: \
2029: if((opcode & 0x90) == 0x90) \
2030: { \
2031: /* STRH rd, [rn - rm]! */ \
2032: arm_access_memory(store, - reg[rm], half_reg, u16, yes, no_op); \
2033: } \
2034: else \
2035: { \
2036: if(opcode & 0x10) \
2037: { \
2038: /* BX rn */ \
2039: arm_decode_branchx(); \
2040: u32 src = reg[rn]; \
2041: if(src & 0x01) \
2042: { \
2043: src -= 1; \
2044: arm_pc_offset_update_direct(src); \
2045: reg[REG_CPSR] |= 0x20; \
2046: goto thumb_loop; \
2047: } \
2048: else \
2049: { \
2050: arm_pc_offset_update_direct(src); \
2051: } \
2052: } \
2053: else \
2054: { \
2055: /* MSR cpsr, rm */ \
2056: arm_psr(reg, store, cpsr); \
2057: } \
2058: } \
2059: break; \
2060: \
2061: case 0x13: \
2062: if((opcode & 0x90) == 0x90) \
2063: { \
2064: switch((opcode >> 5) & 0x03) \
2065: { \
2066: case 1: \
2067: /* LDRH rd, [rn - rm]! */ \
2068: arm_access_memory(load, - reg[rm], half_reg, u16, yes, no_op); \
2069: break; \
2070: \
2071: case 2: \
2072: /* LDRSB rd, [rn - rm]! */ \
2073: arm_access_memory(load, - reg[rm], half_reg, s8, yes, no_op); \
2074: break; \
2075: \
2076: case 3: \
2077: /* LDRSH rd, [rn - rm]! */ \
2078: arm_access_memory(load, - reg[rm], half_reg, s16, yes, no_op); \
2079: break; \
2080: } \
2081: } \
2082: else \
2083: { \
2084: /* TEQ rd, rn, reg_op */ \
2085: arm_data_proc_test_logic(reg[rn] ^ reg_sh, reg); \
2086: } \
2087: break; \
2088: \
2089: case 0x14: \
2090: if((opcode & 0x90) == 0x90) \
2091: { \
2092: if(opcode & 0x20) \
2093: { \
2094: /* STRH rd, [rn - imm] */ \
2095: arm_access_memory(store, - offset, half_imm, u16, no, no_op); \
2096: } \
2097: else \
2098: { \
2099: /* SWPB rd, rm, [rn] */ \
2100: arm_swap(u8); \
2101: } \
2102: } \
2103: else \
2104: { \
2105: /* MRS rd, spsr */ \
2106: arm_psr(reg, read, spsr[reg[CPU_MODE]]); \
2107: } \
2108: break; \
2109: \
2110: case 0x15: \
2111: if((opcode & 0x90) == 0x90) \
2112: { \
2113: switch((opcode >> 5) & 0x03) \
2114: { \
2115: case 1: \
2116: /* LDRH rd, [rn - imm] */ \
2117: arm_access_memory(load, - offset, half_imm, u16, no, no_op); \
2118: break; \
2119: \
2120: case 2: \
2121: /* LDRSB rd, [rn - imm] */ \
2122: arm_access_memory(load, - offset, half_imm, s8, no, no_op); \
2123: break; \
2124: \
2125: case 3: \
2126: /* LDRSH rd, [rn - imm] */ \
2127: arm_access_memory(load, - offset, half_imm, s16, no, no_op); \
2128: break; \
2129: } \
2130: } \
2131: else \
2132: { \
2133: /* CMP rn, reg_op */ \
2134: arm_data_proc_test_sub(reg[rn], reg_sh, reg); \
2135: } \
2136: break; \
2137: \
2138: case 0x16: \
2139: if((opcode & 0x90) == 0x90) \
2140: { \
2141: /* STRH rd, [rn - imm]! */ \
2142: arm_access_memory(store, - offset, half_imm, u16, yes, no_op); \
2143: } \
2144: else \
2145: { \
2146: /* MSR spsr, rm */ \
2147: arm_psr(reg, store, spsr); \
2148: } \
2149: break; \
2150: \
2151: case 0x17: \
2152: if((opcode & 0x90) == 0x90) \
2153: { \
2154: switch((opcode >> 5) & 0x03) \
2155: { \
2156: case 1: \
2157: /* LDRH rd, [rn - imm]! */ \
2158: arm_access_memory(load, - offset, half_imm, u16, yes, no_op); \
2159: break; \
2160: \
2161: case 2: \
2162: /* LDRSB rd, [rn - imm]! */ \
2163: arm_access_memory(load, - offset, half_imm, s8, yes, no_op); \
2164: break; \
2165: \
2166: case 3: \
2167: /* LDRSH rd, [rn - imm]! */ \
2168: arm_access_memory(load, - offset, half_imm, s16, yes, no_op); \
2169: break; \
2170: } \
2171: } \
2172: else \
2173: { \
2174: /* CMN rd, rn, reg_op */ \
2175: arm_data_proc_test_add(reg[rn], reg_sh, reg); \
2176: } \
2177: break; \
2178: \
2179: case 0x18: \
2180: if((opcode & 0x90) == 0x90) \
2181: { \
2182: /* STRH rd, [rn + rm] */ \
2183: arm_access_memory(store, + reg[rm], half_reg, u16, no, no_op); \
2184: } \
2185: else \
2186: { \
2187: /* ORR rd, rn, reg_op */ \
2188: arm_data_proc(reg[rn] | reg_sh, reg); \
2189: } \
2190: break; \
2191: \
2192: case 0x19: \
2193: if((opcode & 0x90) == 0x90) \
2194: { \
2195: switch((opcode >> 5) & 0x03) \
2196: { \
2197: case 1: \
2198: /* LDRH rd, [rn + rm] */ \
2199: arm_access_memory(load, + reg[rm], half_reg, u16, no, no_op); \
2200: break; \
2201: \
2202: case 2: \
2203: /* LDRSB rd, [rn + rm] */ \
2204: arm_access_memory(load, + reg[rm], half_reg, s8, no, no_op); \
2205: break; \
2206: \
2207: case 3: \
2208: /* LDRSH rd, [rn + rm] */ \
2209: arm_access_memory(load, + reg[rm], half_reg, s16, no, no_op); \
2210: break; \
2211: } \
2212: } \
2213: else \
2214: { \
2215: /* ORRS rd, rn, reg_op */ \
2216: arm_data_proc_logic_flags(reg[rn] | reg_sh, reg); \
2217: } \
2218: break; \
2219: \
2220: case 0x1A: \
2221: if((opcode & 0x90) == 0x90) \
2222: { \
2223: /* STRH rd, [rn + rm]! */ \
2224: arm_access_memory(store, + reg[rm], half_reg, u16, yes, no_op); \
2225: } \
2226: else \
2227: { \
2228: /* MOV rd, reg_op */ \
2229: arm_data_proc(reg_sh, reg); \
2230: } \
2231: break; \
2232: \
2233: case 0x1B: \
2234: if((opcode & 0x90) == 0x90) \
2235: { \
2236: switch((opcode >> 5) & 0x03) \
2237: { \
2238: case 1: \
2239: /* LDRH rd, [rn + rm]! */ \
2240: arm_access_memory(load, + reg[rm], half_reg, u16, yes, no_op); \
2241: break; \
2242: \
2243: case 2: \
2244: /* LDRSB rd, [rn + rm]! */ \
2245: arm_access_memory(load, + reg[rm], half_reg, s8, yes, no_op); \
2246: break; \
2247: \
2248: case 3: \
2249: /* LDRSH rd, [rn + rm]! */ \
2250: arm_access_memory(load, + reg[rm], half_reg, s16, yes, no_op); \
2251: break; \
2252: } \
2253: } \
2254: else \
2255: { \
2256: /* MOVS rd, reg_op */ \
2257: arm_data_proc_logic_flags(reg_sh, reg); \
2258: } \
2259: break; \
2260: \
2261: case 0x1C: \
2262: if((opcode & 0x90) == 0x90) \
2263: { \
2264: /* STRH rd, [rn + imm] */ \
2265: arm_access_memory(store, + offset, half_imm, u16, no, no_op); \
2266: } \
2267: else \
2268: { \
2269: /* BIC rd, rn, reg_op */ \
2270: arm_data_proc(reg[rn] & (~reg_sh), reg); \
2271: } \
2272: break; \
2273: \
2274: case 0x1D: \
2275: if((opcode & 0x90) == 0x90) \
2276: { \
2277: switch((opcode >> 5) & 0x03) \
2278: { \
2279: case 1: \
2280: /* LDRH rd, [rn + imm] */ \
2281: arm_access_memory(load, + offset, half_imm, u16, no, no_op); \
2282: break; \
2283: \
2284: case 2: \
2285: /* LDRSB rd, [rn + imm] */ \
2286: arm_access_memory(load, + offset, half_imm, s8, no, no_op); \
2287: break; \
2288: \
2289: case 3: \
2290: /* LDRSH rd, [rn + imm] */ \
2291: arm_access_memory(load, + offset, half_imm, s16, no, no_op); \
2292: break; \
2293: } \
2294: } \
2295: else \
2296: { \
2297: /* BICS rd, rn, reg_op */ \
2298: arm_data_proc_logic_flags(reg[rn] & (~reg_sh), reg); \
2299: } \
2300: break; \
2301: \
2302: case 0x1E: \
2303: if((opcode & 0x90) == 0x90) \
2304: { \
2305: /* STRH rd, [rn + imm]! */ \
2306: arm_access_memory(store, + offset, half_imm, u16, yes, no_op); \
2307: } \
2308: else \
2309: { \
2310: /* MVN rd, reg_op */ \
2311: arm_data_proc(~reg_sh, reg); \
2312: } \
2313: break; \
2314: \
2315: case 0x1F: \
2316: if((opcode & 0x90) == 0x90) \
2317: { \
2318: switch((opcode >> 5) & 0x03) \
2319: { \
2320: case 1: \
2321: /* LDRH rd, [rn + imm]! */ \
2322: arm_access_memory(load, + offset, half_imm, u16, yes, no_op); \
2323: break; \
2324: \
2325: case 2: \
2326: /* LDRSB rd, [rn + imm]! */ \
2327: arm_access_memory(load, + offset, half_imm, s8, yes, no_op); \
2328: break; \
2329: \
2330: case 3: \
2331: /* LDRSH rd, [rn + imm]! */ \
2332: arm_access_memory(load, + offset, half_imm, s16, yes, no_op); \
2333: break; \
2334: } \
2335: } \
2336: else \
2337: { \
2338: /* MVNS rd, rn, reg_op */ \
2339: arm_data_proc_logic_flags(~reg_sh, reg); \
2340: } \
2341: break; \
2342: \
2343: case 0x20: \
2344: /* AND rd, rn, imm */ \
2345: arm_data_proc(reg[rn] & imm, imm); \
2346: break; \
2347: \
2348: case 0x21: \
2349: /* ANDS rd, rn, imm */ \
2350: arm_data_proc_logic_flags(reg[rn] & imm, imm); \
2351: break; \
2352: \
2353: case 0x22: \
2354: /* EOR rd, rn, imm */ \
2355: arm_data_proc(reg[rn] ^ imm, imm); \
2356: break; \
2357: \
2358: case 0x23: \
2359: /* EORS rd, rn, imm */ \
2360: arm_data_proc_logic_flags(reg[rn] ^ imm, imm); \
2361: break; \
2362: \
2363: case 0x24: \
2364: /* SUB rd, rn, imm */ \
2365: arm_data_proc(reg[rn] - imm, imm); \
2366: break; \
2367: \
2368: case 0x25: \
2369: /* SUBS rd, rn, imm */ \
2370: arm_data_proc_sub_flags(reg[rn], imm, imm); \
2371: break; \
2372: \
2373: case 0x26: \
2374: /* RSB rd, rn, imm */ \
2375: arm_data_proc(imm - reg[rn], imm); \
2376: break; \
2377: \
2378: case 0x27: \
2379: /* RSBS rd, rn, imm */ \
2380: arm_data_proc_sub_flags(imm, reg[rn], imm); \
2381: break; \
2382: \
2383: case 0x28: \
2384: /* ADD rd, rn, imm */ \
2385: arm_data_proc(reg[rn] + imm, imm); \
2386: break; \
2387: \
2388: case 0x29: \
2389: /* ADDS rd, rn, imm */ \
2390: arm_data_proc_add_flags(reg[rn], imm, imm); \
2391: break; \
2392: \
2393: case 0x2A: \
2394: /* ADC rd, rn, imm */ \
2395: arm_data_proc(reg[rn] + imm + c_flag, imm); \
2396: break; \
2397: \
2398: case 0x2B: \
2399: /* ADCS rd, rn, imm */ \
2400: arm_data_proc_add_flags(reg[rn] + imm, c_flag, imm); \
2401: break; \
2402: \
2403: case 0x2C: \
2404: /* SBC rd, rn, imm */ \
2405: arm_data_proc(reg[rn] - (imm + (c_flag ^ 1)), imm); \
2406: break; \
2407: \
2408: case 0x2D: \
2409: /* SBCS rd, rn, imm */ \
2410: arm_data_proc_sub_flags(reg[rn], (imm + (c_flag ^ 1)), imm); \
2411: break; \
2412: \
2413: case 0x2E: \
2414: /* RSC rd, rn, imm */ \
2415: arm_data_proc(imm - (reg[rn] + (c_flag ^ 1)), imm); \
2416: break; \
2417: \
2418: case 0x2F: \
2419: /* RSCS rd, rn, imm */ \
2420: arm_data_proc_sub_flags(imm, reg[rn] + (c_flag ^ 1), imm); \
2421: break; \
2422: \
2423: case 0x30 ... 0x31: \
2424: /* TST rn, imm */ \
2425: arm_data_proc_test_logic(reg[rn] & imm, imm); \
2426: break; \
2427: \
2428: case 0x32: \
2429: /* MSR cpsr, imm */ \
2430: arm_psr(imm, store, cpsr); \
2431: break; \
2432: \
2433: case 0x33: \
2434: /* TEQ rn, imm */ \
2435: arm_data_proc_test_logic(reg[rn] ^ imm, imm); \
2436: break; \
2437: \
2438: case 0x34 ... 0x35: \
2439: /* CMP rn, imm */ \
2440: arm_data_proc_test_sub(reg[rn], imm, imm); \
2441: break; \
2442: \
2443: case 0x36: \
2444: /* MSR spsr, imm */ \
2445: arm_psr(imm, store, spsr); \
2446: break; \
2447: \
2448: case 0x37: \
2449: /* CMN rn, imm */ \
2450: arm_data_proc_test_add(reg[rn], imm, imm); \
2451: break; \
2452: \
2453: case 0x38: \
2454: /* ORR rd, rn, imm */ \
2455: arm_data_proc(reg[rn] | imm, imm); \
2456: break; \
2457: \
2458: case 0x39: \
2459: /* ORRS rd, rn, imm */ \
2460: arm_data_proc_logic_flags(reg[rn] | imm, imm); \
2461: break; \
2462: \
2463: case 0x3A: \
2464: /* MOV rd, imm */ \
2465: arm_data_proc(imm, imm); \
2466: break; \
2467: \
2468: case 0x3B: \
2469: /* MOVS rd, imm */ \
2470: arm_data_proc_logic_flags(imm, imm); \
2471: break; \
2472: \
2473: case 0x3C: \
2474: /* BIC rd, rn, imm */ \
2475: arm_data_proc(reg[rn] & (~imm), imm); \
2476: break; \
2477: \
2478: case 0x3D: \
2479: /* BICS rd, rn, imm */ \
2480: arm_data_proc_logic_flags(reg[rn] & (~imm), imm); \
2481: break; \
2482: \
2483: case 0x3E: \
2484: /* MVN rd, imm */ \
2485: arm_data_proc(~imm, imm); \
2486: break; \
2487: \
2488: case 0x3F: \
2489: /* MVNS rd, imm */ \
2490: arm_data_proc_logic_flags(~imm, imm); \
2491: break; \
2492: \
2493: case 0x40: \
2494: /* STR rd, [rn], -imm */ \
2495: arm_access_memory(store, no_op, imm, u32, yes, - offset); \
2496: break; \
2497: \
2498: case 0x41: \
2499: /* LDR rd, [rn], -imm */ \
2500: arm_access_memory(load, no_op, imm, u32, yes, - offset); \
2501: break; \
2502: \
2503: case 0x42: \
2504: /* STRT rd, [rn], -imm */ \
2505: arm_access_memory(store, no_op, imm, u32, yes, - offset); \
2506: break; \
2507: \
2508: case 0x43: \
2509: /* LDRT rd, [rn], -imm */ \
2510: arm_access_memory(load, no_op, imm, u32, yes, - offset); \
2511: break; \
2512: \
2513: case 0x44: \
2514: /* STRB rd, [rn], -imm */ \
2515: arm_access_memory(store, no_op, imm, u8, yes, - offset); \
2516: break; \
2517: \
2518: case 0x45: \
2519: /* LDRB rd, [rn], -imm */ \
2520: arm_access_memory(load, no_op, imm, u8, yes, - offset); \
2521: break; \
2522: \
2523: case 0x46: \
2524: /* STRBT rd, [rn], -imm */ \
2525: arm_access_memory(store, no_op, imm, u8, yes, - offset); \
2526: break; \
2527: \
2528: case 0x47: \
2529: /* LDRBT rd, [rn], -imm */ \
2530: arm_access_memory(load, no_op, imm, u8, yes, - offset); \
2531: break; \
2532: \
2533: case 0x48: \
2534: /* STR rd, [rn], +imm */ \
2535: arm_access_memory(store, no_op, imm, u32, yes, + offset); \
2536: break; \
2537: \
2538: case 0x49: \
2539: /* LDR rd, [rn], +imm */ \
2540: arm_access_memory(load, no_op, imm, u32, yes, + offset); \
2541: break; \
2542: \
2543: case 0x4A: \
2544: /* STRT rd, [rn], +imm */ \
2545: arm_access_memory(store, no_op, imm, u32, yes, + offset); \
2546: break; \
2547: \
2548: case 0x4B: \
2549: /* LDRT rd, [rn], +imm */ \
2550: arm_access_memory(load, no_op, imm, u32, yes, + offset); \
2551: break; \
2552: \
2553: case 0x4C: \
2554: /* STRB rd, [rn], +imm */ \
2555: arm_access_memory(store, no_op, imm, u8, yes, + offset); \
2556: break; \
2557: \
2558: case 0x4D: \
2559: /* LDRB rd, [rn], +imm */ \
2560: arm_access_memory(load, no_op, imm, u8, yes, + offset); \
2561: break; \
2562: \
2563: case 0x4E: \
2564: /* STRBT rd, [rn], +imm */ \
2565: arm_access_memory(store, no_op, imm, u8, yes, + offset); \
2566: break; \
2567: \
2568: case 0x4F: \
2569: /* LDRBT rd, [rn], +imm */ \
2570: arm_access_memory(load, no_op, imm, u8, yes, + offset); \
2571: break; \
2572: \
2573: case 0x50: \
2574: /* STR rd, [rn - imm] */ \
2575: arm_access_memory(store, - offset, imm, u32, no, no_op); \
2576: break; \
2577: \
2578: case 0x51: \
2579: /* LDR rd, [rn - imm] */ \
2580: arm_access_memory(load, - offset, imm, u32, no, no_op); \
2581: break; \
2582: \
2583: case 0x52: \
2584: /* STR rd, [rn - imm]! */ \
2585: arm_access_memory(store, - offset, imm, u32, yes, no_op); \
2586: break; \
2587: \
2588: case 0x53: \
2589: /* LDR rd, [rn - imm]! */ \
2590: arm_access_memory(load, - offset, imm, u32, yes, no_op); \
2591: break; \
2592: \
2593: case 0x54: \
2594: /* STRB rd, [rn - imm] */ \
2595: arm_access_memory(store, - offset, imm, u8, no, no_op); \
2596: break; \
2597: \
2598: case 0x55: \
2599: /* LDRB rd, [rn - imm] */ \
2600: arm_access_memory(load, - offset, imm, u8, no, no_op); \
2601: break; \
2602: \
2603: case 0x56: \
2604: /* STRB rd, [rn - imm]! */ \
2605: arm_access_memory(store, - offset, imm, u8, yes, no_op); \
2606: break; \
2607: \
2608: case 0x57: \
2609: /* LDRB rd, [rn - imm]! */ \
2610: arm_access_memory(load, - offset, imm, u8, yes, no_op); \
2611: break; \
2612: \
2613: case 0x58: \
2614: /* STR rd, [rn + imm] */ \
2615: arm_access_memory(store, + offset, imm, u32, no, no_op); \
2616: break; \
2617: \
2618: case 0x59: \
2619: /* LDR rd, [rn + imm] */ \
2620: arm_access_memory(load, + offset, imm, u32, no, no_op); \
2621: break; \
2622: \
2623: case 0x5A: \
2624: /* STR rd, [rn + imm]! */ \
2625: arm_access_memory(store, + offset, imm, u32, yes, no_op); \
2626: break; \
2627: \
2628: case 0x5B: \
2629: /* LDR rd, [rn + imm]! */ \
2630: arm_access_memory(load, + offset, imm, u32, yes, no_op); \
2631: break; \
2632: \
2633: case 0x5C: \
2634: /* STRB rd, [rn + imm] */ \
2635: arm_access_memory(store, + offset, imm, u8, no, no_op); \
2636: break; \
2637: \
2638: case 0x5D: \
2639: /* LDRB rd, [rn + imm] */ \
2640: arm_access_memory(load, + offset, imm, u8, no, no_op); \
2641: break; \
2642: \
2643: case 0x5E: \
2644: /* STRB rd, [rn + imm]! */ \
2645: arm_access_memory(store, + offset, imm, u8, yes, no_op); \
2646: break; \
2647: \
2648: case 0x5F: \
2649: /* LDRBT rd, [rn + imm]! */ \
2650: arm_access_memory(load, + offset, imm, u8, yes, no_op); \
2651: break; \
2652: \
2653: case 0x60: \
2654: /* STR rd, [rn], -reg_op */ \
2655: arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); \
2656: break; \
2657: \
2658: case 0x61: \
2659: /* LDR rd, [rn], -reg_op */ \
2660: arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); \
2661: break; \
2662: \
2663: case 0x62: \
2664: /* STRT rd, [rn], -reg_op */ \
2665: arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); \
2666: break; \
2667: \
2668: case 0x63: \
2669: /* LDRT rd, [rn], -reg_op */ \
2670: arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); \
2671: break; \
2672: \
2673: case 0x64: \
2674: /* STRB rd, [rn], -reg_op */ \
2675: arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); \
2676: break; \
2677: \
2678: case 0x65: \
2679: /* LDRB rd, [rn], -reg_op */ \
2680: arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); \
2681: break; \
2682: \
2683: case 0x66: \
2684: /* STRBT rd, [rn], -reg_op */ \
2685: arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); \
2686: break; \
2687: \
2688: case 0x67: \
2689: /* LDRBT rd, [rn], -reg_op */ \
2690: arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); \
2691: break; \
2692: \
2693: case 0x68: \
2694: /* STR rd, [rn], +reg_op */ \
2695: arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); \
2696: break; \
2697: \
2698: case 0x69: \
2699: /* LDR rd, [rn], +reg_op */ \
2700: arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); \
2701: break; \
2702: \
2703: case 0x6A: \
2704: /* STRT rd, [rn], +reg_op */ \
2705: arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); \
2706: break; \
2707: \
2708: case 0x6B: \
2709: /* LDRT rd, [rn], +reg_op */ \
2710: arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); \
2711: break; \
2712: \
2713: case 0x6C: \
2714: /* STRB rd, [rn], +reg_op */ \
2715: arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); \
2716: break; \
2717: \
2718: case 0x6D: \
2719: /* LDRB rd, [rn], +reg_op */ \
2720: arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); \
2721: break; \
2722: \
2723: case 0x6E: \
2724: /* STRBT rd, [rn], +reg_op */ \
2725: arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); \
2726: break; \
2727: \
2728: case 0x6F: \
2729: /* LDRBT rd, [rn], +reg_op */ \
2730: arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); \
2731: break; \
2732: \
2733: case 0x70: \
2734: /* STR rd, [rn - reg_op] */ \
2735: arm_access_memory(store, - reg_offset, reg, u32, no, no_op); \
2736: break; \
2737: \
2738: case 0x71: \
2739: /* LDR rd, [rn - reg_op] */ \
2740: arm_access_memory(load, - reg_offset, reg, u32, no, no_op); \
2741: break; \
2742: \
2743: case 0x72: \
2744: /* STR rd, [rn - reg_op]! */ \
2745: arm_access_memory(store, - reg_offset, reg, u32, yes, no_op); \
2746: break; \
2747: \
2748: case 0x73: \
2749: /* LDR rd, [rn - reg_op]! */ \
2750: arm_access_memory(load, - reg_offset, reg, u32, yes, no_op); \
2751: break; \
2752: \
2753: case 0x74: \
2754: /* STRB rd, [rn - reg_op] */ \
2755: arm_access_memory(store, - reg_offset, reg, u8, no, no_op); \
2756: break; \
2757: \
2758: case 0x75: \
2759: /* LDRB rd, [rn - reg_op] */ \
2760: arm_access_memory(load, - reg_offset, reg, u8, no, no_op); \
2761: break; \
2762: \
2763: case 0x76: \
2764: /* STRB rd, [rn - reg_op]! */ \
2765: arm_access_memory(store, - reg_offset, reg, u8, yes, no_op); \
2766: break; \
2767: \
2768: case 0x77: \
2769: /* LDRB rd, [rn - reg_op]! */ \
2770: arm_access_memory(load, - reg_offset, reg, u8, yes, no_op); \
2771: break; \
2772: \
2773: case 0x78: \
2774: /* STR rd, [rn + reg_op] */ \
2775: arm_access_memory(store, + reg_offset, reg, u32, no, no_op); \
2776: break; \
2777: \
2778: case 0x79: \
2779: /* LDR rd, [rn + reg_op] */ \
2780: arm_access_memory(load, + reg_offset, reg, u32, no, no_op); \
2781: break; \
2782: \
2783: case 0x7A: \
2784: /* STR rd, [rn + reg_op]! */ \
2785: arm_access_memory(store, + reg_offset, reg, u32, yes, no_op); \
2786: break; \
2787: \
2788: case 0x7B: \
2789: /* LDR rd, [rn + reg_op]! */ \
2790: arm_access_memory(load, + reg_offset, reg, u32, yes, no_op); \
2791: break; \
2792: \
2793: case 0x7C: \
2794: /* STRB rd, [rn + reg_op] */ \
2795: arm_access_memory(store, + reg_offset, reg, u8, no, no_op); \
2796: break; \
2797: \
2798: case 0x7D: \
2799: /* LDRB rd, [rn + reg_op] */ \
2800: arm_access_memory(load, + reg_offset, reg, u8, no, no_op); \
2801: break; \
2802: \
2803: case 0x7E: \
2804: /* STRB rd, [rn + reg_op]! */ \
2805: arm_access_memory(store, + reg_offset, reg, u8, yes, no_op); \
2806: break; \
2807: \
2808: case 0x7F: \
2809: /* LDRBT rd, [rn + reg_op]! */ \
2810: arm_access_memory(load, + reg_offset, reg, u8, yes, no_op); \
2811: break; \
2812: \
2813: case 0x80: \
2814: /* STMDA rn, rlist */ \
2815: arm_block_memory(store, down_a, no, no); \
2816: break; \
2817: \
2818: case 0x81: \
2819: /* LDMDA rn, rlist */ \
2820: arm_block_memory(load, down_a, no, no); \
2821: break; \
2822: \
2823: case 0x82: \
2824: /* STMDA rn!, rlist */ \
2825: arm_block_memory(store, down_a, down, no); \
2826: break; \
2827: \
2828: case 0x83: \
2829: /* LDMDA rn!, rlist */ \
2830: arm_block_memory(load, down_a, down, no); \
2831: break; \
2832: \
2833: case 0x84: \
2834: /* STMDA rn, rlist^ */ \
2835: arm_block_memory(store, down_a, no, yes); \
2836: break; \
2837: \
2838: case 0x85: \
2839: /* LDMDA rn, rlist^ */ \
2840: arm_block_memory(load, down_a, no, yes); \
2841: break; \
2842: \
2843: case 0x86: \
2844: /* STMDA rn!, rlist^ */ \
2845: arm_block_memory(store, down_a, down, yes); \
2846: break; \
2847: \
2848: case 0x87: \
2849: /* LDMDA rn!, rlist^ */ \
2850: arm_block_memory(load, down_a, down, yes); \
2851: break; \
2852: \
2853: case 0x88: \
2854: /* STMIA rn, rlist */ \
2855: arm_block_memory(store, no, no, no); \
2856: break; \
2857: \
2858: case 0x89: \
2859: /* LDMIA rn, rlist */ \
2860: arm_block_memory(load, no, no, no); \
2861: break; \
2862: \
2863: case 0x8A: \
2864: /* STMIA rn!, rlist */ \
2865: arm_block_memory(store, no, up, no); \
2866: break; \
2867: \
2868: case 0x8B: \
2869: /* LDMIA rn!, rlist */ \
2870: arm_block_memory(load, no, up, no); \
2871: break; \
2872: \
2873: case 0x8C: \
2874: /* STMIA rn, rlist^ */ \
2875: arm_block_memory(store, no, no, yes); \
2876: break; \
2877: \
2878: case 0x8D: \
2879: /* LDMIA rn, rlist^ */ \
2880: arm_block_memory(load, no, no, yes); \
2881: break; \
2882: \
2883: case 0x8E: \
2884: /* STMIA rn!, rlist^ */ \
2885: arm_block_memory(store, no, up, yes); \
2886: break; \
2887: \
2888: case 0x8F: \
2889: /* LDMIA rn!, rlist^ */ \
2890: arm_block_memory(load, no, up, yes); \
2891: break; \
2892: \
2893: case 0x90: \
2894: /* STMDB rn, rlist */ \
2895: arm_block_memory(store, down_b, no, no); \
2896: break; \
2897: \
2898: case 0x91: \
2899: /* LDMDB rn, rlist */ \
2900: arm_block_memory(load, down_b, no, no); \
2901: break; \
2902: \
2903: case 0x92: \
2904: /* STMDB rn!, rlist */ \
2905: arm_block_memory(store, down_b, down, no); \
2906: break; \
2907: \
2908: case 0x93: \
2909: /* LDMDB rn!, rlist */ \
2910: arm_block_memory(load, down_b, down, no); \
2911: break; \
2912: \
2913: case 0x94: \
2914: /* STMDB rn, rlist^ */ \
2915: arm_block_memory(store, down_b, no, yes); \
2916: break; \
2917: \
2918: case 0x95: \
2919: /* LDMDB rn, rlist^ */ \
2920: arm_block_memory(load, down_b, no, yes); \
2921: break; \
2922: \
2923: case 0x96: \
2924: /* STMDB rn!, rlist^ */ \
2925: arm_block_memory(store, down_b, down, yes); \
2926: break; \
2927: \
2928: case 0x97: \
2929: /* LDMDB rn!, rlist^ */ \
2930: arm_block_memory(load, down_b, down, yes); \
2931: break; \
2932: \
2933: case 0x98: \
2934: /* STMIB rn, rlist */ \
2935: arm_block_memory(store, up, no, no); \
2936: break; \
2937: \
2938: case 0x99: \
2939: /* LDMIB rn, rlist */ \
2940: arm_block_memory(load, up, no, no); \
2941: break; \
2942: \
2943: case 0x9A: \
2944: /* STMIB rn!, rlist */ \
2945: arm_block_memory(store, up, up, no); \
2946: break; \
2947: \
2948: case 0x9B: \
2949: /* LDMIB rn!, rlist */ \
2950: arm_block_memory(load, up, up, no); \
2951: break; \
2952: \
2953: case 0x9C: \
2954: /* STMIB rn, rlist^ */ \
2955: arm_block_memory(store, up, no, yes); \
2956: break; \
2957: \
2958: case 0x9D: \
2959: /* LDMIB rn, rlist^ */ \
2960: arm_block_memory(load, up, no, yes); \
2961: break; \
2962: \
2963: case 0x9E: \
2964: /* STMIB rn!, rlist^ */ \
2965: arm_block_memory(store, up, up, yes); \
2966: break; \
2967: \
2968: case 0x9F: \
2969: /* LDMIB rn!, rlist^ */ \
2970: arm_block_memory(load, up, up, yes); \
2971: break; \
2972: \
2973: case 0xA0 ... 0xAF: \
2974: { \
2975: /* B offset */ \
2976: arm_decode_branch(); \
2977: arm_pc_offset_update(offset + 8); \
2978: break; \
2979: } \
2980: \
2981: case 0xB0 ... 0xBF: \
2982: { \
2983: /* BL offset */ \
2984: arm_decode_branch(); \
2985: reg[REG_LR] = pc + 4; \
2986: arm_pc_offset_update(offset + 8); \
2987: break; \
2988: } \
2989: \
2990: case 0xC0 ... 0xEF: \
2991: /* coprocessor instructions, reserved on GBA */ \
2992: break; \
2993: \
2994: case 0xF0 ... 0xFF: \
2995: { \
2996: /* SWI comment */ \
2997: u32 swi_comment = opcode & 0x00FFFFFF; \
2998: \
2999: switch(swi_comment >> 16) \
3000: { \
3001: /* Jump to BIOS SWI handler */ \
3002: case 0x00 ... 0x2A: \
3003: reg_mode[MODE_SUPERVISOR][6] = pc + 4; \
3004: collapse_flags(); \
3005: spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; \
3006: reg[REG_PC] = 0x00000008; \
3007: arm_update_pc(); \
3008: reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13; \
3009: set_cpu_mode(MODE_SUPERVISOR); \
3010: break; \
3011: } \
3012: break; \
3013: } \
3014: } \
3015: \
3016: skip_instruction: \
3017:
3018: #define execute_thumb_instruction() \
3019: check_pc_region(); \
3020: pc &= ~0x01; \
3021: opcode = ADDRESS16(pc_address_block, (pc & 0x7FFF)); \
3022: switch((opcode >> 8) & 0xFF) \
3023: { \
3024: case 0x00 ... 0x07: \
3025: /* LSL rd, rs, offset */ \
3026: thumb_shift(shift, lsl, imm); \
3027: break; \
3028: \
3029: case 0x08 ... 0x0F: \
3030: /* LSR rd, rs, offset */ \
3031: thumb_shift(shift, lsr, imm); \
3032: break; \
3033: \
3034: case 0x10 ... 0x17: \
3035: /* ASR rd, rs, offset */ \
3036: thumb_shift(shift, asr, imm); \
3037: break; \
3038: \
3039: case 0x18 ... 0x19: \
3040: /* ADD rd, rs, rn */ \
3041: thumb_add(add_sub, rd, reg[rs], reg[rn]); \
3042: break; \
3043: \
3044: case 0x1A ... 0x1B: \
3045: /* SUB rd, rs, rn */ \
3046: thumb_sub(add_sub, rd, reg[rs], reg[rn]); \
3047: break; \
3048: \
3049: case 0x1C ... 0x1D: \
3050: /* ADD rd, rs, imm */ \
3051: thumb_add(add_sub_imm, rd, reg[rs], imm); \
3052: break; \
3053: \
3054: case 0x1E ... 0x1F: \
3055: /* SUB rd, rs, imm */ \
3056: thumb_sub(add_sub_imm, rd, reg[rs], imm); \
3057: break; \
3058: \
3059: case 0x20: \
3060: /* MOV r0, imm */ \
3061: thumb_logic(imm, 0, imm); \
3062: break; \
3063: \
3064: case 0x21: \
3065: /* MOV r1, imm */ \
3066: thumb_logic(imm, 1, imm); \
3067: break; \
3068: \
3069: case 0x22: \
3070: /* MOV r2, imm */ \
3071: thumb_logic(imm, 2, imm); \
3072: break; \
3073: \
3074: case 0x23: \
3075: /* MOV r3, imm */ \
3076: thumb_logic(imm, 3, imm); \
3077: break; \
3078: \
3079: case 0x24: \
3080: /* MOV r4, imm */ \
3081: thumb_logic(imm, 4, imm); \
3082: break; \
3083: \
3084: case 0x25: \
3085: /* MOV r5, imm */ \
3086: thumb_logic(imm, 5, imm); \
3087: break; \
3088: \
3089: case 0x26: \
3090: /* MOV r6, imm */ \
3091: thumb_logic(imm, 6, imm); \
3092: break; \
3093: \
3094: case 0x27: \
3095: /* MOV r7, imm */ \
3096: thumb_logic(imm, 7, imm); \
3097: break; \
3098: \
3099: case 0x28: \
3100: /* CMP r0, imm */ \
3101: thumb_test_sub(imm, reg[0], imm); \
3102: break; \
3103: \
3104: case 0x29: \
3105: /* CMP r1, imm */ \
3106: thumb_test_sub(imm, reg[1], imm); \
3107: break; \
3108: \
3109: case 0x2A: \
3110: /* CMP r2, imm */ \
3111: thumb_test_sub(imm, reg[2], imm); \
3112: break; \
3113: \
3114: case 0x2B: \
3115: /* CMP r3, imm */ \
3116: thumb_test_sub(imm, reg[3], imm); \
3117: break; \
3118: \
3119: case 0x2C: \
3120: /* CMP r4, imm */ \
3121: thumb_test_sub(imm, reg[4], imm); \
3122: break; \
3123: \
3124: case 0x2D: \
3125: /* CMP r5, imm */ \
3126: thumb_test_sub(imm, reg[5], imm); \
3127: break; \
3128: \
3129: case 0x2E: \
3130: /* CMP r6, imm */ \
3131: thumb_test_sub(imm, reg[6], imm); \
3132: break; \
3133: \
3134: case 0x2F: \
3135: /* CMP r7, imm */ \
3136: thumb_test_sub(imm, reg[7], imm); \
3137: break; \
3138: \
3139: case 0x30: \
3140: /* ADD r0, imm */ \
3141: thumb_add(imm, 0, reg[0], imm); \
3142: break; \
3143: \
3144: case 0x31: \
3145: /* ADD r1, imm */ \
3146: thumb_add(imm, 1, reg[1], imm); \
3147: break; \
3148: \
3149: case 0x32: \
3150: /* ADD r2, imm */ \
3151: thumb_add(imm, 2, reg[2], imm); \
3152: break; \
3153: \
3154: case 0x33: \
3155: /* ADD r3, imm */ \
3156: thumb_add(imm, 3, reg[3], imm); \
3157: break; \
3158: \
3159: case 0x34: \
3160: /* ADD r4, imm */ \
3161: thumb_add(imm, 4, reg[4], imm); \
3162: break; \
3163: \
3164: case 0x35: \
3165: /* ADD r5, imm */ \
3166: thumb_add(imm, 5, reg[5], imm); \
3167: break; \
3168: \
3169: case 0x36: \
3170: /* ADD r6, imm */ \
3171: thumb_add(imm, 6, reg[6], imm); \
3172: break; \
3173: \
3174: case 0x37: \
3175: /* ADD r7, imm */ \
3176: thumb_add(imm, 7, reg[7], imm); \
3177: break; \
3178: \
3179: case 0x38: \
3180: /* SUB r0, imm */ \
3181: thumb_sub(imm, 0, reg[0], imm); \
3182: break; \
3183: \
3184: case 0x39: \
3185: /* SUB r1, imm */ \
3186: thumb_sub(imm, 1, reg[1], imm); \
3187: break; \
3188: \
3189: case 0x3A: \
3190: /* SUB r2, imm */ \
3191: thumb_sub(imm, 2, reg[2], imm); \
3192: break; \
3193: \
3194: case 0x3B: \
3195: /* SUB r3, imm */ \
3196: thumb_sub(imm, 3, reg[3], imm); \
3197: break; \
3198: \
3199: case 0x3C: \
3200: /* SUB r4, imm */ \
3201: thumb_sub(imm, 4, reg[4], imm); \
3202: break; \
3203: \
3204: case 0x3D: \
3205: /* SUB r5, imm */ \
3206: thumb_sub(imm, 5, reg[5], imm); \
3207: break; \
3208: \
3209: case 0x3E: \
3210: /* SUB r6, imm */ \
3211: thumb_sub(imm, 6, reg[6], imm); \
3212: break; \
3213: \
3214: case 0x3F: \
3215: /* SUB r7, imm */ \
3216: thumb_sub(imm, 7, reg[7], imm); \
3217: break; \
3218: \
3219: case 0x40: \
3220: switch((opcode >> 6) & 0x03) \
3221: { \
3222: case 0x00: \
3223: /* AND rd, rs */ \
3224: thumb_logic(alu_op, rd, (reg[rd] & reg[rs])); \
3225: break; \
3226: \
3227: case 0x01: \
3228: /* EOR rd, rs */ \
3229: thumb_logic(alu_op, rd, (reg[rd] ^ reg[rs])); \
3230: break; \
3231: \
3232: case 0x02: \
3233: /* LSL rd, rs */ \
3234: thumb_shift(alu_op, lsl, reg); \
3235: break; \
3236: \
3237: case 0x03: \
3238: /* LSR rd, rs */ \
3239: thumb_shift(alu_op, lsr, reg); \
3240: break; \
3241: } \
3242: break; \
3243: \
3244: case 0x41: \
3245: switch((opcode >> 6) & 0x03) \
3246: { \
3247: case 0x00: \
3248: /* ASR rd, rs */ \
3249: thumb_shift(alu_op, asr, reg); \
3250: break; \
3251: \
3252: case 0x01: \
3253: /* ADC rd, rs */ \
3254: thumb_add(alu_op, rd, (reg[rd] + reg[rs]), c_flag); \
3255: break; \
3256: \
3257: case 0x02: \
3258: /* SBC rd, rs */ \
3259: thumb_subc(alu_op, rd, reg[rd], reg[rs], c_flag); \
3260: break; \
3261: \
3262: case 0x03: \
3263: /* ROR rd, rs */ \
3264: thumb_shift(alu_op, ror, reg); \
3265: break; \
3266: } \
3267: break; \
3268: \
3269: case 0x42: \
3270: switch((opcode >> 6) & 0x03) \
3271: { \
3272: case 0x00: \
3273: /* TST rd, rs */ \
3274: thumb_test_logic(alu_op, (reg[rd] & reg[rs])); \
3275: break; \
3276: \
3277: case 0x01: \
3278: /* NEG rd, rs */ \
3279: thumb_sub(alu_op, rd, 0, reg[rs]); \
3280: break; \
3281: \
3282: case 0x02: \
3283: /* CMP rd, rs */ \
3284: thumb_test_sub(alu_op, reg[rd], reg[rs]); \
3285: break; \
3286: \
3287: case 0x03: \
3288: /* CMN rd, rs */ \
3289: thumb_test_add(alu_op, reg[rd], reg[rs]); \
3290: break; \
3291: } \
3292: break; \
3293: \
3294: case 0x43: \
3295: switch((opcode >> 6) & 0x03) \
3296: { \
3297: case 0x00: \
3298: /* ORR rd, rs */ \
3299: thumb_logic(alu_op, rd, reg[rd] | reg[rs]); \
3300: break; \
3301: \
3302: case 0x01: \
3303: /* MUL rd, rs */ \
3304: thumb_logic(alu_op, rd, (reg[rd] * reg[rs])); \
3305: break; \
3306: \
3307: case 0x02: \
3308: /* BIC rd, rs */ \
3309: thumb_logic(alu_op, rd, (reg[rd] & (~reg[rs]))); \
3310: break; \
3311: \
3312: case 0x03: \
3313: /* MVN rd, rs */ \
3314: thumb_logic(alu_op, rd, (~reg[rs])); \
3315: break; \
3316: } \
3317: break; \
3318: \
3319: case 0x44: \
3320: /* ADD rd, rs */ \
3321: thumb_hireg_op((reg[rd] + reg[rs])); \
3322: break; \
3323: \
3324: case 0x45: \
3325: /* CMP rd, rs */ \
3326: { \
3327: thumb_pc_offset(4); \
3328: thumb_decode_hireg_op(); \
3329: u32 _sa = reg[rd]; \
3330: u32 _sb = reg[rs]; \
3331: u32 dest = _sa - _sb; \
3332: thumb_pc_offset(-2); \
3333: calculate_flags_sub(dest, _sa, _sb); \
3334: } \
3335: break; \
3336: \
3337: case 0x46: \
3338: /* MOV rd, rs */ \
3339: thumb_hireg_op(reg[rs]); \
3340: break; \
3341: \
3342: case 0x47: \
3343: /* BX rs */ \
3344: { \
3345: thumb_decode_hireg_op(); \
3346: u32 src; \
3347: thumb_pc_offset(4); \
3348: src = reg[rs]; \
3349: if(src & 0x01) \
3350: { \
3351: src -= 1; \
3352: thumb_pc_offset_update_direct(src); \
3353: } \
3354: else \
3355: { \
3356: /* Switch to ARM mode */ \
3357: thumb_pc_offset_update_direct(src); \
3358: reg[REG_CPSR] &= ~0x20; \
3359: collapse_flags(); \
3360: goto arm_loop; \
3361: } \
3362: } \
3363: break; \
3364: \
3365: case 0x48: \
3366: /* LDR r0, [pc + imm] */ \
3367: thumb_access_memory(load, imm, ((pc & ~2) + (imm * 4) + 4), reg[0], u32);\
3368: break; \
3369: \
3370: case 0x49: \
3371: /* LDR r1, [pc + imm] */ \
3372: thumb_access_memory(load, imm, ((pc & ~2) + (imm * 4) + 4), reg[1], u32);\
3373: break; \
3374: \
3375: case 0x4A: \
3376: /* LDR r2, [pc + imm] */ \
3377: thumb_access_memory(load, imm, ((pc & ~2) + (imm * 4) + 4), reg[2], u32);\
3378: break; \
3379: \
3380: case 0x4B: \
3381: /* LDR r3, [pc + imm] */ \
3382: thumb_access_memory(load, imm, ((pc & ~2) + (imm * 4) + 4), reg[3], u32);\
3383: break; \
3384: \
3385: case 0x4C: \
3386: /* LDR r4, [pc + imm] */ \
3387: thumb_access_memory(load, imm, ((pc & ~2) + (imm * 4) + 4), reg[4], u32);\
3388: break; \
3389: \
3390: case 0x4D: \
3391: /* LDR r5, [pc + imm] */ \
3392: thumb_access_memory(load, imm, ((pc & ~2) + (imm * 4) + 4), reg[5], u32);\
3393: break; \
3394: \
3395: case 0x4E: \
3396: /* LDR r6, [pc + imm] */ \
3397: thumb_access_memory(load, imm, ((pc & ~2) + (imm * 4) + 4), reg[6], u32);\
3398: break; \
3399: \
3400: case 0x4F: \
3401: /* LDR r7, [pc + imm] */ \
3402: thumb_access_memory(load, imm, ((pc & ~2) + (imm * 4) + 4), reg[7], u32);\
3403: break; \
3404: \
3405: case 0x50 ... 0x51: \
3406: /* STR rd, [rb + ro] */ \
3407: thumb_access_memory(store, mem_reg, (reg[rb] + reg[ro]), reg[rd], u32); \
3408: break; \
3409: \
3410: case 0x52 ... 0x53: \
3411: /* STRH rd, [rb + ro] */ \
3412: thumb_access_memory(store, mem_reg, (reg[rb] + reg[ro]), reg[rd], u16); \
3413: break; \
3414: \
3415: case 0x54 ... 0x55: \
3416: /* STRB rd, [rb + ro] */ \
3417: thumb_access_memory(store, mem_reg, (reg[rb] + reg[ro]), reg[rd], u8); \
3418: break; \
3419: \
3420: case 0x56 ... 0x57: \
3421: /* LDSB rd, [rb + ro] */ \
3422: thumb_access_memory(load, mem_reg, (reg[rb] + reg[ro]), reg[rd], s8); \
3423: break; \
3424: \
3425: case 0x58 ... 0x59: \
3426: /* LDR rd, [rb + ro] */ \
3427: thumb_access_memory(load, mem_reg, (reg[rb] + reg[ro]), reg[rd], u32); \
3428: break; \
3429: \
3430: case 0x5A ... 0x5B: \
3431: /* LDRH rd, [rb + ro] */ \
3432: thumb_access_memory(load, mem_reg, (reg[rb] + reg[ro]), reg[rd], u16); \
3433: break; \
3434: \
3435: case 0x5C ... 0x5D: \
3436: /* LDRB rd, [rb + ro] */ \
3437: thumb_access_memory(load, mem_reg, (reg[rb] + reg[ro]), reg[rd], u8); \
3438: break; \
3439: \
3440: case 0x5E ... 0x5F: \
3441: /* LDSH rd, [rb + ro] */ \
3442: thumb_access_memory(load, mem_reg, (reg[rb] + reg[ro]), reg[rd], s16); \
3443: break; \
3444: \
3445: case 0x60 ... 0x67: \
3446: /* STR rd, [rb + imm] */ \
3447: thumb_access_memory(store, mem_imm, (reg[rb] + (imm * 4)), reg[rd], u32);\
3448: break; \
3449: \
3450: case 0x68 ... 0x6F: \
3451: /* LDR rd, [rb + imm] */ \
3452: thumb_access_memory(load, mem_imm, (reg[rb] + (imm * 4)), reg[rd], u32);\
3453: break; \
3454: \
3455: case 0x70 ... 0x77: \
3456: /* STRB rd, [rb + imm] */ \
3457: thumb_access_memory(store, mem_imm, (reg[rb] + imm), reg[rd], u8); \
3458: break; \
3459: \
3460: case 0x78 ... 0x7F: \
3461: /* LDRB rd, [rb + imm] */ \
3462: thumb_access_memory(load, mem_imm, (reg[rb] + imm), reg[rd], u8); \
3463: break; \
3464: \
3465: case 0x80 ... 0x87: \
3466: /* STRH rd, [rb + imm] */ \
3467: thumb_access_memory(store, mem_imm, (reg[rb] + (imm * 2)), reg[rd], u16);\
3468: break; \
3469: \
3470: case 0x88 ... 0x8F: \
3471: /* LDRH rd, [rb + imm] */ \
3472: thumb_access_memory(load, mem_imm, (reg[rb] + (imm * 2)), reg[rd], u16);\
3473: break; \
3474: \
3475: case 0x90: \
3476: /* STR r0, [sp + imm] */ \
3477: thumb_access_memory(store, imm, (reg[REG_SP] + (imm * 4)), reg[0], u32);\
3478: break; \
3479: \
3480: case 0x91: \
3481: /* STR r1, [sp + imm] */ \
3482: thumb_access_memory(store, imm, (reg[REG_SP] + (imm * 4)), reg[1], u32);\
3483: break; \
3484: \
3485: case 0x92: \
3486: /* STR r2, [sp + imm] */ \
3487: thumb_access_memory(store, imm, (reg[REG_SP] + (imm * 4)), reg[2], u32);\
3488: break; \
3489: \
3490: case 0x93: \
3491: /* STR r3, [sp + imm] */ \
3492: thumb_access_memory(store, imm, (reg[REG_SP] + (imm * 4)), reg[3], u32);\
3493: break; \
3494: \
3495: case 0x94: \
3496: /* STR r4, [sp + imm] */ \
3497: thumb_access_memory(store, imm, (reg[REG_SP] + (imm * 4)), reg[4], u32);\
3498: break; \
3499: \
3500: case 0x95: \
3501: /* STR r5, [sp + imm] */ \
3502: thumb_access_memory(store, imm, (reg[REG_SP] + (imm * 4)), reg[5], u32);\
3503: break; \
3504: \
3505: case 0x96: \
3506: /* STR r6, [sp + imm] */ \
3507: thumb_access_memory(store, imm, (reg[REG_SP] + (imm * 4)), reg[6], u32);\
3508: break; \
3509: \
3510: case 0x97: \
3511: /* STR r7, [sp + imm] */ \
3512: thumb_access_memory(store, imm, (reg[REG_SP] + (imm * 4)), reg[7], u32);\
3513: break; \
3514: \
3515: case 0x98: \
3516: /* LDR r0, [sp + imm] */ \
3517: thumb_access_memory(load, imm, (reg[REG_SP] + (imm * 4)), reg[0], u32); \
3518: break; \
3519: \
3520: case 0x99: \
3521: /* LDR r1, [sp + imm] */ \
3522: thumb_access_memory(load, imm, (reg[REG_SP] + (imm * 4)), reg[1], u32); \
3523: break; \
3524: \
3525: case 0x9A: \
3526: /* LDR r2, [sp + imm] */ \
3527: thumb_access_memory(load, imm, (reg[REG_SP] + (imm * 4)), reg[2], u32); \
3528: break; \
3529: \
3530: case 0x9B: \
3531: /* LDR r3, [sp + imm] */ \
3532: thumb_access_memory(load, imm, (reg[REG_SP] + (imm * 4)), reg[3], u32); \
3533: break; \
3534: \
3535: case 0x9C: \
3536: /* LDR r4, [sp + imm] */ \
3537: thumb_access_memory(load, imm, (reg[REG_SP] + (imm * 4)), reg[4], u32); \
3538: break; \
3539: \
3540: case 0x9D: \
3541: /* LDR r5, [sp + imm] */ \
3542: thumb_access_memory(load, imm, (reg[REG_SP] + (imm * 4)), reg[5], u32); \
3543: break; \
3544: \
3545: case 0x9E: \
3546: /* LDR r6, [sp + imm] */ \
3547: thumb_access_memory(load, imm, (reg[REG_SP] + (imm * 4)), reg[6], u32); \
3548: break; \
3549: \
3550: case 0x9F: \
3551: /* LDR r7, [sp + imm] */ \
3552: thumb_access_memory(load, imm, (reg[REG_SP] + (imm * 4)), reg[7], u32); \
3553: break; \
3554: \
3555: case 0xA0: \
3556: /* ADD r0, pc, +imm */ \
3557: thumb_add_noflags(imm, 0, ((pc & ~2) + 4), (imm * 4)); \
3558: break; \
3559: \
3560: case 0xA1: \
3561: /* ADD r1, pc, +imm */ \
3562: thumb_add_noflags(imm, 1, ((pc & ~2) + 4), (imm * 4)); \
3563: break; \
3564: \
3565: case 0xA2: \
3566: /* ADD r2, pc, +imm */ \
3567: thumb_add_noflags(imm, 2, ((pc & ~2) + 4), (imm * 4)); \
3568: break; \
3569: \
3570: case 0xA3: \
3571: /* ADD r3, pc, +imm */ \
3572: thumb_add_noflags(imm, 3, ((pc & ~2) + 4), (imm * 4)); \
3573: break; \
3574: \
3575: case 0xA4: \
3576: /* ADD r4, pc, +imm */ \
3577: thumb_add_noflags(imm, 4, ((pc & ~2) + 4), (imm * 4)); \
3578: break; \
3579: \
3580: case 0xA5: \
3581: /* ADD r5, pc, +imm */ \
3582: thumb_add_noflags(imm, 5, ((pc & ~2) + 4), (imm * 4)); \
3583: break; \
3584: \
3585: case 0xA6: \
3586: /* ADD r6, pc, +imm */ \
3587: thumb_add_noflags(imm, 6, ((pc & ~2) + 4), (imm * 4)); \
3588: break; \
3589: \
3590: case 0xA7: \
3591: /* ADD r7, pc, +imm */ \
3592: thumb_add_noflags(imm, 7, ((pc & ~2) + 4), (imm * 4)); \
3593: break; \
3594: \
3595: case 0xA8: \
3596: /* ADD r0, sp, +imm */ \
3597: thumb_add_noflags(imm, 0, reg[REG_SP], (imm * 4)); \
3598: break; \
3599: \
3600: case 0xA9: \
3601: /* ADD r1, sp, +imm */ \
3602: thumb_add_noflags(imm, 1, reg[REG_SP], (imm * 4)); \
3603: break; \
3604: \
3605: case 0xAA: \
3606: /* ADD r2, sp, +imm */ \
3607: thumb_add_noflags(imm, 2, reg[REG_SP], (imm * 4)); \
3608: break; \
3609: \
3610: case 0xAB: \
3611: /* ADD r3, sp, +imm */ \
3612: thumb_add_noflags(imm, 3, reg[REG_SP], (imm * 4)); \
3613: break; \
3614: \
3615: case 0xAC: \
3616: /* ADD r4, sp, +imm */ \
3617: thumb_add_noflags(imm, 4, reg[REG_SP], (imm * 4)); \
3618: break; \
3619: \
3620: case 0xAD: \
3621: /* ADD r5, sp, +imm */ \
3622: thumb_add_noflags(imm, 5, reg[REG_SP], (imm * 4)); \
3623: break; \
3624: \
3625: case 0xAE: \
3626: /* ADD r6, sp, +imm */ \
3627: thumb_add_noflags(imm, 6, reg[REG_SP], (imm * 4)); \
3628: break; \
3629: \
3630: case 0xAF: \
3631: /* ADD r7, sp, +imm */ \
3632: thumb_add_noflags(imm, 7, reg[REG_SP], (imm * 4)); \
3633: break; \
3634: \
3635: case 0xB0 ... 0xB3: \
3636: if((opcode >> 7) & 0x01) \
3637: { \
3638: /* ADD sp, -imm */ \
3639: thumb_add_noflags(add_sp, 13, reg[REG_SP], (imm * -4)); \
3640: } \
3641: else \
3642: { \
3643: /* ADD sp, +imm */ \
3644: thumb_add_noflags(add_sp, 13, reg[REG_SP], (imm * 4)); \
3645: } \
3646: break; \
3647: \
3648: case 0xB4: \
3649: /* PUSH rlist */ \
3650: thumb_block_memory(store, down, no_op, 13); \
3651: break; \
3652: \
3653: case 0xB5: \
3654: /* PUSH rlist, lr */ \
3655: thumb_block_memory(store, push_lr, push_lr, 13); \
3656: break; \
3657: \
3658: case 0xBC: \
3659: /* POP rlist */ \
3660: thumb_block_memory(load, no_op, up, 13); \
3661: break; \
3662: \
3663: case 0xBD: \
3664: /* POP rlist, pc */ \
3665: thumb_block_memory(load, no_op, pop_pc, 13); \
3666: break; \
3667: \
3668: case 0xC0: \
3669: /* STMIA r0!, rlist */ \
3670: thumb_block_memory(store, no_op, up, 0); \
3671: break; \
3672: \
3673: case 0xC1: \
3674: /* STMIA r1!, rlist */ \
3675: thumb_block_memory(store, no_op, up, 1); \
3676: break; \
3677: \
3678: case 0xC2: \
3679: /* STMIA r2!, rlist */ \
3680: thumb_block_memory(store, no_op, up, 2); \
3681: break; \
3682: \
3683: case 0xC3: \
3684: /* STMIA r3!, rlist */ \
3685: thumb_block_memory(store, no_op, up, 3); \
3686: break; \
3687: \
3688: case 0xC4: \
3689: /* STMIA r4!, rlist */ \
3690: thumb_block_memory(store, no_op, up, 4); \
3691: break; \
3692: \
3693: case 0xC5: \
3694: /* STMIA r5!, rlist */ \
3695: thumb_block_memory(store, no_op, up, 5); \
3696: break; \
3697: \
3698: case 0xC6: \
3699: /* STMIA r6!, rlist */ \
3700: thumb_block_memory(store, no_op, up, 6); \
3701: break; \
3702: \
3703: case 0xC7: \
3704: /* STMIA r7!, rlist */ \
3705: thumb_block_memory(store, no_op, up, 7); \
3706: break; \
3707: \
3708: case 0xC8: \
3709: /* LDMIA r0!, rlist */ \
3710: thumb_block_memory(load, no_op, up, 0); \
3711: break; \
3712: \
3713: case 0xC9: \
3714: /* LDMIA r1!, rlist */ \
3715: thumb_block_memory(load, no_op, up, 1); \
3716: break; \
3717: \
3718: case 0xCA: \
3719: /* LDMIA r2!, rlist */ \
3720: thumb_block_memory(load, no_op, up, 2); \
3721: break; \
3722: \
3723: case 0xCB: \
3724: /* LDMIA r3!, rlist */ \
3725: thumb_block_memory(load, no_op, up, 3); \
3726: break; \
3727: \
3728: case 0xCC: \
3729: /* LDMIA r4!, rlist */ \
3730: thumb_block_memory(load, no_op, up, 4); \
3731: break; \
3732: \
3733: case 0xCD: \
3734: /* LDMIA r5!, rlist */ \
3735: thumb_block_memory(load, no_op, up, 5); \
3736: break; \
3737: \
3738: case 0xCE: \
3739: /* LDMIA r6!, rlist */ \
3740: thumb_block_memory(load, no_op, up, 6); \
3741: break; \
3742: \
3743: case 0xCF: \
3744: /* LDMIA r7!, rlist */ \
3745: thumb_block_memory(load, no_op, up, 7); \
3746: break; \
3747: \
3748: case 0xD0: \
3749: /* BEQ label */ \
3750: thumb_conditional_branch((z_flag == 1)); \
3751: break; \
3752: \
3753: case 0xD1: \
3754: /* BNE label */ \
3755: thumb_conditional_branch((z_flag == 0)); \
3756: break; \
3757: \
3758: case 0xD2: \
3759: /* BCS label */ \
3760: thumb_conditional_branch((c_flag == 1)); \
3761: break; \
3762: \
3763: case 0xD3: \
3764: /* BCC label */ \
3765: thumb_conditional_branch((c_flag == 0)); \
3766: break; \
3767: \
3768: case 0xD4: \
3769: /* BMI label */ \
3770: thumb_conditional_branch((n_flag == 1)); \
3771: break; \
3772: \
3773: case 0xD5: \
3774: /* BPL label */ \
3775: thumb_conditional_branch((n_flag == 0)); \
3776: break; \
3777: \
3778: case 0xD6: \
3779: /* BVS label */ \
3780: thumb_conditional_branch((v_flag == 1)); \
3781: break; \
3782: \
3783: case 0xD7: \
3784: /* BVC label */ \
3785: thumb_conditional_branch((v_flag == 0)); \
3786: break; \
3787: \
3788: case 0xD8: \
3789: /* BHI label */ \
3790: thumb_conditional_branch((c_flag & (z_flag == 0))); \
3791: break; \
3792: \
3793: case 0xD9: \
3794: /* BLS label */ \
3795: thumb_conditional_branch(((c_flag == 0) | z_flag)); \
3796: break; \
3797: \
3798: case 0xDA: \
3799: /* BGE label */ \
3800: thumb_conditional_branch((n_flag == v_flag)); \
3801: break; \
3802: \
3803: case 0xDB: \
3804: /* BLT label */ \
3805: thumb_conditional_branch((n_flag != v_flag)); \
3806: break; \
3807: \
3808: case 0xDC: \
3809: /* BGT label */ \
3810: thumb_conditional_branch(((z_flag == 0) & (n_flag == v_flag))); \
3811: break; \
3812: \
3813: case 0xDD: \
3814: /* BLE label */ \
3815: thumb_conditional_branch((z_flag | (n_flag != v_flag))); \
3816: break; \
3817: \
3818: case 0xDF: \
3819: { \
3820: /* SWI comment */ \
3821: u32 swi_comment = opcode & 0xFF; \
3822: \
3823: switch(swi_comment) \
3824: { \
3825: default: \
3826: \
3827: reg_mode[MODE_SUPERVISOR][6] = pc + 2; \
3828: spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; \
3829: reg[REG_PC] = 0x00000008; \
3830: thumb_update_pc(); \
3831: reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13; \
3832: set_cpu_mode(MODE_SUPERVISOR); \
3833: collapse_flags(); \
3834: goto arm_loop; \
3835: } \
3836: break; \
3837: } \
3838: \
3839: case 0xE0 ... 0xE7: \
3840: { \
3841: /* B label */ \
3842: thumb_decode_branch(); \
3843: thumb_pc_offset_update((((s32)(offset << 21) >> 20) + 4)); \
3844: break; \
3845: } \
3846: \
3847: case 0xF0 ... 0xF7: \
3848: { \
3849: /* (low word) BL label */ \
3850: thumb_decode_branch(); \
3851: reg[REG_LR] = pc + 4 + ((s32)(offset << 21) >> 9); \
3852: thumb_pc_offset(2); \
3853: break; \
3854: } \
3855: \
3856: case 0xF8 ... 0xFF: \
3857: { \
3858: /* (high word) BL label */ \
3859: thumb_decode_branch(); \
3860: u32 lr = (pc + 2) | 0x01; \
3861: pc = reg[REG_LR] + (offset * 2); \
3862: reg[REG_LR] = lr; \
3863: reg[REG_PC] = pc; \
3864: break; \
3865: } \
3866: } \
3867:
3868: void execute_arm(u32 cycles)
3869: {
3870: u32 pc = reg[REG_PC];
3871: u32 opcode;
3872: u32 condition;
3873: u32 n_flag, z_flag, c_flag, v_flag;
3874: u32 pc_region = (pc >> 15);
3875: u8 *pc_address_block = memory_map_read[pc_region];
3876: u32 new_pc_region;
3877: s32 cycles_remaining;
3878: u32 cycles_per_instruction = global_cycles_per_instruction;
3879: CPU_ALERT_TYPE cpu_alert;
3880:
3881: if(pc_address_block == NULL)
3882: pc_address_block = load_gamepak_page(pc_region & 0x3FF);
3883:
3884: while(1)
3885: {
3886: cycles_remaining = cycles;
3887: pc = reg[REG_PC];
3888: extract_flags();
3889:
3890: if(reg[REG_CPSR] & 0x20)
3891: goto thumb_loop;
3892:
3893: do
3894: {
3895: arm_loop:
3896:
3897: collapse_flags();
3898: cycles_per_instruction = global_cycles_per_instruction;
3899:
3900: execute_arm_instruction();
3901: cycles_remaining -= cycles_per_instruction;
3902: } while(cycles_remaining > 0);
3903:
3904: collapse_flags();
3905: cycles = update_gba();
3906: continue;
3907:
3908: do
3909: {
3910: thumb_loop:
3911:
3912: collapse_flags();
3913:
3914: execute_thumb_instruction();
3915: cycles_remaining -= cycles_per_instruction;
3916: } while(cycles_remaining > 0);
3917:
3918: collapse_flags();
3919: cycles = update_gba();
3920: continue;
3921:
3922: alert:
3923:
3924: if(cpu_alert == CPU_ALERT_IRQ)
3925: {
3926: cycles = cycles_remaining;
3927: }
3928: else
3929: {
3930: collapse_flags();
3931:
3932: while(reg[CPU_HALT_STATE] != CPU_ACTIVE)
3933: {
3934: cycles = update_gba();
3935: }
3936: }
3937: }
3938: }
3939:
3940: #endif
3941: