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