Add copyright message to gles_video
[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() \
bbba3209 365 u32 reg_sh = 0; \
2823a4c8 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() \
bbba3209 454 u32 reg_sh = 0; \
2823a4c8 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() \
bbba3209 607 u32 reg_offset = 0; \
2823a4c8 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) && \
bbba3209 963 (map = memory_map_read[_address >> 15])) \
2823a4c8 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{ \
bbba3209 1019 u32 _address = address; \
1020 u8 *map = memory_map_read[_address >> 15]; \
1021 if(_address < 0x10000000) \
2823a4c8 1022 { \
bbba3209 1023 memory_region_access_read_u32[_address >> 24]++; \
2823a4c8 1024 memory_reads_u32++; \
1025 } \
1026 if(map) \
1027 { \
bbba3209 1028 dest = address32(map, _address & 0x7FFF); \
2823a4c8 1029 } \
1030 else \
1031 { \
bbba3209 1032 dest = read_memory32(_address); \
2823a4c8 1033 } \
1034} \
1035
1036#define store_aligned32(address, value) \
1037{ \
bbba3209 1038 u32 _address = address; \
1039 u8 *map = memory_map_write[_address >> 15]; \
1040 if(_address < 0x10000000) \
2823a4c8 1041 { \
bbba3209 1042 memory_region_access_write_u32[_address >> 24]++; \
2823a4c8 1043 memory_writes_u32++; \
1044 } \
1045 if(map) \
1046 { \
bbba3209 1047 address32(map, _address & 0x7FFF) = value; \
2823a4c8 1048 } \
1049 else \
1050 { \
bbba3209 1051 cpu_alert = write_memory32(_address, value); \
2823a4c8 1052 if(cpu_alert) \
1053 goto alert; \
1054 } \
1055} \
1056
1057#define load_memory_u8(address, dest) \
1058 fast_read_memory(8, u8, address, dest) \
1059
1060#define load_memory_u16(address, dest) \
1061 fast_read_memory(16, u16, address, dest) \
1062
1063#define load_memory_u32(address, dest) \
1064 fast_read_memory(32, u32, address, dest) \
1065
1066#define load_memory_s8(address, dest) \
1067 fast_read_memory(8, s8, address, dest) \
1068
1069#define load_memory_s16(address, dest) \
1070 fast_read_memory_s16(address, dest) \
1071
1072#define store_memory_u8(address, value) \
1073 fast_write_memory(8, u8, address, value) \
1074
1075#define store_memory_u16(address, value) \
1076 fast_write_memory(16, u16, address, value) \
1077
1078#define store_memory_u32(address, value) \
1079 fast_write_memory(32, u32, address, value) \
1080
1081#define no_op \
1082
1083#define arm_access_memory_writeback_yes(off_op) \
1084 reg[rn] = address off_op \
1085
1086#define arm_access_memory_writeback_no(off_op) \
1087
1088#define arm_access_memory_pc_preadjust_load() \
1089
1090#define arm_access_memory_pc_preadjust_store() \
1091 u32 reg_op = reg[rd]; \
1092 if(rd == 15) \
1093 reg_op += 4 \
1094
1095#define arm_access_memory_pc_postadjust_load() \
1096 arm_update_pc() \
1097
1098#define arm_access_memory_pc_postadjust_store() \
1099
1100#define load_reg_op reg[rd] \
1101
1102#define store_reg_op reg_op \
1103
1104#define arm_access_memory(access_type, off_op, off_type, mem_type, \
1105 wb, wb_off_op) \
1106{ \
1107 arm_pc_offset(8); \
1108 arm_data_trans_##off_type(); \
1109 u32 address = reg[rn] off_op; \
1110 arm_access_memory_pc_preadjust_##access_type(); \
1111 \
1112 arm_pc_offset(-4); \
1113 arm_access_memory_writeback_##wb(wb_off_op); \
1114 access_type##_memory_##mem_type(address, access_type##_reg_op); \
1115 arm_access_memory_pc_postadjust_##access_type(); \
1116} \
1117
1118#define word_bit_count(word) \
1119 (bit_count[word >> 8] + bit_count[word & 0xFF]) \
1120
1121#define sprint_no(access_type, offset_type, writeback_type) \
1122
1123#define sprint_yes(access_type, offset_type, writeback_type) \
1124 printf("sbit on %s %s %s\n", #access_type, #offset_type, #writeback_type) \
1125
1126#define arm_block_writeback_load() \
1127 if(!((reg_list >> rn) & 0x01)) \
1128 { \
1129 reg[rn] = address; \
1130 } \
1131
1132#define arm_block_writeback_store() \
1133 reg[rn] = address \
1134
1135#define arm_block_writeback_yes(access_type) \
1136 arm_block_writeback_##access_type() \
1137
1138#define arm_block_writeback_no(access_type) \
1139
1140#define load_block_memory(address, dest) \
1141 dest = address32(address_region, (address + offset) & 0x7FFF) \
1142
1143#define store_block_memory(address, dest) \
1144 address32(address_region, (address + offset) & 0x7FFF) = dest \
1145
1146#define arm_block_memory_offset_down_a() \
1147 (base - (word_bit_count(reg_list) * 4) + 4) \
1148
1149#define arm_block_memory_offset_down_b() \
1150 (base - (word_bit_count(reg_list) * 4)) \
1151
1152#define arm_block_memory_offset_no() \
1153 (base) \
1154
1155#define arm_block_memory_offset_up() \
1156 (base + 4) \
1157
1158#define arm_block_memory_writeback_down() \
1159 reg[rn] = base - (word_bit_count(reg_list) * 4) \
1160
1161#define arm_block_memory_writeback_up() \
1162 reg[rn] = base + (word_bit_count(reg_list) * 4) \
1163
1164#define arm_block_memory_writeback_no() \
1165
1166#define arm_block_memory_load_pc() \
1167 load_aligned32(address, pc); \
1168 reg[REG_PC] = pc \
1169
1170#define arm_block_memory_store_pc() \
1171 store_aligned32(address, pc + 4) \
1172
1173#define arm_block_memory(access_type, offset_type, writeback_type, s_bit) \
1174{ \
1175 arm_decode_block_trans(); \
1176 u32 base = reg[rn]; \
1177 u32 address = arm_block_memory_offset_##offset_type() & 0xFFFFFFFC; \
1178 u32 i; \
1179 \
1180 arm_block_memory_writeback_##writeback_type(); \
1181 \
1182 for(i = 0; i < 15; i++) \
1183 { \
1184 if((reg_list >> i) & 0x01) \
1185 { \
1186 access_type##_aligned32(address, reg[i]); \
1187 address += 4; \
1188 } \
1189 } \
1190 \
1191 arm_pc_offset(4); \
1192 if(reg_list & 0x8000) \
1193 { \
1194 arm_block_memory_##access_type##_pc(); \
1195 } \
1196} \
1197
1198#define arm_swap(type) \
1199{ \
1200 arm_decode_swap(); \
1201 u32 temp; \
1202 load_memory_##type(reg[rn], temp); \
1203 store_memory_##type(reg[rn], reg[rm]); \
1204 reg[rd] = temp; \
1205 arm_pc_offset(4); \
1206} \
1207
1208#define arm_next_instruction() \
1209{ \
1210 arm_pc_offset(4); \
1211 goto skip_instruction; \
1212} \
1213
1214#define thumb_update_pc() \
1215 pc = reg[REG_PC] \
1216
1217#define thumb_pc_offset(val) \
1218 pc += val; \
1219 reg[REG_PC] = pc \
1220
1221#define thumb_pc_offset_update(val) \
1222 pc += val; \
1223 reg[REG_PC] = pc \
1224
1225#define thumb_pc_offset_update_direct(val) \
1226 pc = val; \
1227 reg[REG_PC] = pc \
1228
1229// Types: add_sub, add_sub_imm, alu_op, imm
1230// Affects N/Z/C/V flags
1231
1232#define thumb_add(type, dest_reg, src_a, src_b) \
1233{ \
1234 thumb_decode_##type(); \
1235 const u32 _sa = src_a; \
1236 const u32 _sb = src_b; \
1237 u32 dest = _sa + _sb; \
bbba3209 1238 calculate_flags_add(dest, _sa, _sb); \
2823a4c8 1239 reg[dest_reg] = dest; \
1240 thumb_pc_offset(2); \
1241} \
1242
1243#define thumb_add_noflags(type, dest_reg, src_a, src_b) \
1244{ \
1245 thumb_decode_##type(); \
bbba3209 1246 u32 dest = (src_a) + (src_b); \
2823a4c8 1247 reg[dest_reg] = dest; \
1248 thumb_pc_offset(2); \
1249} \
1250
1251#define thumb_sub(type, dest_reg, src_a, src_b) \
1252{ \
1253 thumb_decode_##type(); \
1254 const u32 _sa = src_a; \
1255 const u32 _sb = src_b; \
1256 u32 dest = _sa - _sb; \
bbba3209 1257 calculate_flags_sub(dest, _sa, _sb); \
2823a4c8 1258 reg[dest_reg] = dest; \
1259 thumb_pc_offset(2); \
1260} \
1261
1262// Affects N/Z flags
1263
1264#define thumb_logic(type, dest_reg, expr) \
1265{ \
1266 thumb_decode_##type(); \
1267 u32 dest = expr; \
1268 calculate_flags_logic(dest); \
1269 reg[dest_reg] = dest; \
1270 thumb_pc_offset(2); \
1271} \
1272
1273// Decode types: shift, alu_op
1274// Operation types: lsl, lsr, asr, ror
1275// Affects N/Z/C flags
1276
1277#define thumb_shift_lsl_reg() \
1278 u32 shift = reg[rs]; \
1279 u32 dest = reg[rd]; \
1280 if(shift != 0) \
1281 { \
1282 if(shift > 31) \
1283 { \
1284 if(shift == 32) \
1285 c_flag = dest & 0x01; \
1286 else \
1287 c_flag = 0; \
1288 dest = 0; \
1289 } \
1290 else \
1291 { \
1292 c_flag = (dest >> (32 - shift)) & 0x01; \
1293 dest <<= shift; \
1294 } \
1295 } \
1296
1297#define thumb_shift_lsr_reg() \
1298 u32 shift = reg[rs]; \
1299 u32 dest = reg[rd]; \
1300 if(shift != 0) \
1301 { \
1302 if(shift > 31) \
1303 { \
1304 if(shift == 32) \
1305 c_flag = dest >> 31; \
1306 else \
1307 c_flag = 0; \
1308 dest = 0; \
1309 } \
1310 else \
1311 { \
1312 c_flag = (dest >> (shift - 1)) & 0x01; \
1313 dest >>= shift; \
1314 } \
1315 } \
1316
1317#define thumb_shift_asr_reg() \
1318 u32 shift = reg[rs]; \
1319 u32 dest = reg[rd]; \
1320 if(shift != 0) \
1321 { \
1322 if(shift > 31) \
1323 { \
1324 dest = (s32)dest >> 31; \
1325 c_flag = dest & 0x01; \
1326 } \
1327 else \
1328 { \
1329 c_flag = (dest >> (shift - 1)) & 0x01; \
1330 dest = (s32)dest >> shift; \
1331 } \
1332 } \
1333
1334#define thumb_shift_ror_reg() \
1335 u32 shift = reg[rs]; \
1336 u32 dest = reg[rd]; \
1337 if(shift != 0) \
1338 { \
1339 c_flag = (dest >> (shift - 1)) & 0x01; \
1340 ror(dest, dest, shift); \
1341 } \
1342
1343#define thumb_shift_lsl_imm() \
1344 u32 dest = reg[rs]; \
1345 if(imm != 0) \
1346 { \
1347 c_flag = (dest >> (32 - imm)) & 0x01; \
1348 dest <<= imm; \
1349 } \
1350
1351#define thumb_shift_lsr_imm() \
1352 u32 dest; \
1353 if(imm == 0) \
1354 { \
1355 dest = 0; \
1356 c_flag = reg[rs] >> 31; \
1357 } \
1358 else \
1359 { \
1360 dest = reg[rs]; \
1361 c_flag = (dest >> (imm - 1)) & 0x01; \
1362 dest >>= imm; \
1363 } \
1364
1365#define thumb_shift_asr_imm() \
1366 u32 dest; \
1367 if(imm == 0) \
1368 { \
1369 dest = (s32)reg[rs] >> 31; \
1370 c_flag = dest & 0x01; \
1371 } \
1372 else \
1373 { \
1374 dest = reg[rs]; \
1375 c_flag = (dest >> (imm - 1)) & 0x01; \
1376 dest = (s32)dest >> imm; \
1377 } \
1378
1379#define thumb_shift_ror_imm() \
1380 u32 dest = reg[rs]; \
1381 if(imm == 0) \
1382 { \
1383 u32 old_c_flag = c_flag; \
1384 c_flag = dest & 0x01; \
1385 dest = (dest >> 1) | (old_c_flag << 31); \
1386 } \
1387 else \
1388 { \
1389 c_flag = (dest >> (imm - 1)) & 0x01; \
1390 ror(dest, dest, imm); \
1391 } \
1392
1393#define thumb_shift(decode_type, op_type, value_type) \
1394{ \
1395 thumb_decode_##decode_type(); \
1396 thumb_shift_##op_type##_##value_type(); \
1397 calculate_flags_logic(dest); \
1398 reg[rd] = dest; \
1399 thumb_pc_offset(2); \
1400} \
1401
1402#define thumb_test_add(type, src_a, src_b) \
1403{ \
1404 thumb_decode_##type(); \
1405 const u32 _sa = src_a; \
1406 const u32 _sb = src_b; \
1407 u32 dest = _sa + _sb; \
1408 calculate_flags_add(dest, src_a, src_b); \
1409 thumb_pc_offset(2); \
1410} \
1411
1412#define thumb_test_sub(type, src_a, src_b) \
1413{ \
1414 thumb_decode_##type(); \
1415 const u32 _sa = src_a; \
1416 const u32 _sb = src_b; \
1417 u32 dest = _sa - _sb; \
1418 calculate_flags_sub(dest, src_a, src_b); \
1419 thumb_pc_offset(2); \
1420} \
1421
1422#define thumb_test_logic(type, expr) \
1423{ \
1424 thumb_decode_##type(); \
1425 u32 dest = expr; \
1426 calculate_flags_logic(dest); \
1427 thumb_pc_offset(2); \
1428}
1429
1430#define thumb_hireg_op(expr) \
1431{ \
1432 thumb_pc_offset(4); \
1433 thumb_decode_hireg_op(); \
1434 u32 dest = expr; \
1435 thumb_pc_offset(-2); \
1436 if(rd == 15) \
1437 { \
1438 reg[REG_PC] = dest & ~0x01; \
1439 thumb_update_pc(); \
1440 } \
1441 else \
1442 { \
1443 reg[rd] = dest; \
1444 } \
1445} \
1446
1447// Operation types: imm, mem_reg, mem_imm
1448
1449#define thumb_access_memory(access_type, op_type, address, reg_op, \
1450 mem_type) \
1451{ \
1452 thumb_decode_##op_type(); \
1453 access_type##_memory_##mem_type(address, reg_op); \
1454 thumb_pc_offset(2); \
1455} \
1456
1457#define thumb_block_address_preadjust_no_op() \
1458
1459#define thumb_block_address_preadjust_up() \
1460 address += bit_count[reg_list] * 4 \
1461
1462#define thumb_block_address_preadjust_down() \
1463 address -= bit_count[reg_list] * 4 \
1464
1465#define thumb_block_address_preadjust_push_lr() \
1466 address -= (bit_count[reg_list] + 1) * 4 \
1467
1468#define thumb_block_address_postadjust_no_op() \
1469
1470#define thumb_block_address_postadjust_up() \
1471 address += offset \
1472
1473#define thumb_block_address_postadjust_down() \
1474 address -= offset \
1475
1476#define thumb_block_address_postadjust_pop_pc() \
1477 load_memory_u32(address + offset, pc); \
1478 pc &= ~0x01; \
1479 reg[REG_PC] = pc; \
1480 address += offset + 4 \
1481
1482#define thumb_block_address_postadjust_push_lr() \
1483 store_memory_u32(address + offset, reg[REG_LR]); \
1484
1485#define thumb_block_memory_wb_load(base_reg) \
1486 if(!((reg_list >> base_reg) & 0x01)) \
1487 { \
1488 reg[base_reg] = address; \
1489 } \
1490
1491#define thumb_block_memory_wb_store(base_reg) \
1492 reg[base_reg] = address \
1493
1494#define thumb_block_memory(access_type, pre_op, post_op, base_reg) \
1495{ \
1496 u32 i; \
1497 u32 offset = 0; \
1498 thumb_decode_rlist(); \
1499 using_register(thumb, base_reg, memory_base); \
1500 u32 address = reg[base_reg] & ~0x03; \
1501 thumb_block_address_preadjust_##pre_op(); \
1502 \
1503 for(i = 0; i < 8; i++) \
1504 { \
1505 if((reg_list >> i) & 1) \
1506 { \
1507 access_type##_aligned32(address + offset, reg[i]); \
1508 offset += 4; \
1509 } \
1510 } \
1511 \
1512 thumb_pc_offset(2); \
1513 \
1514 thumb_block_address_postadjust_##post_op(); \
1515 thumb_block_memory_wb_##access_type(base_reg); \
1516} \
1517
1518#define thumb_conditional_branch(condition) \
1519{ \
1520 thumb_decode_branch_cond(); \
1521 if(condition) \
1522 { \
1523 thumb_pc_offset((offset * 2) + 4); \
1524 } \
1525 else \
1526 { \
1527 thumb_pc_offset(2); \
1528 } \
1529} \
1530
1531// When a mode change occurs from non-FIQ to non-FIQ retire the current
1532// reg[13] and reg[14] into reg_mode[cpu_mode][5] and reg_mode[cpu_mode][6]
1533// respectively and load into reg[13] and reg[14] reg_mode[new_mode][5] and
1534// reg_mode[new_mode][6]. When swapping to/from FIQ retire/load reg[8]
1535// through reg[14] to/from reg_mode[MODE_FIQ][0] through reg_mode[MODE_FIQ][6].
1536
1537u32 reg_mode[7][7];
1538
1539u32 cpu_modes[32] =
1540{
1541 MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID,
1542 MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID,
1543 MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID,
1544 MODE_INVALID, MODE_USER, MODE_FIQ, MODE_IRQ, MODE_SUPERVISOR, MODE_INVALID,
1545 MODE_INVALID, MODE_INVALID, MODE_ABORT, MODE_INVALID, MODE_INVALID,
1546 MODE_INVALID, MODE_INVALID, MODE_UNDEFINED, MODE_INVALID, MODE_INVALID,
1547 MODE_USER
1548};
1549
1550u32 cpu_modes_cpsr[7] = { 0x10, 0x11, 0x12, 0x13, 0x17, 0x1B, 0x1F };
1551
1552// When switching modes set spsr[new_mode] to cpsr. Modifying PC as the
1553// target of a data proc instruction will set cpsr to spsr[cpu_mode].
1554
1555u32 initial_reg[64];
1556u32 *reg = initial_reg;
1557u32 spsr[6];
1558
1559// ARM/Thumb mode is stored in the flags directly, this is simpler than
1560// shadowing it since it has a constant 1bit represenation.
1561
1562char *reg_names[16] =
1563{
1564 " r0", " r1", " r2", " r3", " r4", " r5", " r6", " r7",
1565 " r8", " r9", "r10", " fp", " ip", " sp", " lr", " pc"
1566};
1567
1568char *cpu_mode_names[] =
1569{
1570 "user", "irq", "fiq", "svsr", "abrt", "undf", "invd"
1571};
1572
1573
1574#define execute_arm_instruction() \
1575 using_instruction(arm); \
1576 check_pc_region(); \
1577 pc &= ~0x03; \
1578 opcode = address32(pc_address_block, (pc & 0x7FFF)); \
1579 condition = opcode >> 28; \
1580 \
1581 switch(condition) \
1582 { \
1583 case 0x0: \
1584 /* EQ */ \
1585 if(!z_flag) \
1586 arm_next_instruction(); \
1587 break; \
1588 \
1589 case 0x1: \
1590 /* NE */ \
1591 if(z_flag) \
1592 arm_next_instruction(); \
1593 break; \
1594 \
1595 case 0x2: \
1596 /* CS */ \
1597 if(!c_flag) \
1598 arm_next_instruction(); \
1599 break; \
1600 \
1601 case 0x3: \
1602 /* CC */ \
1603 if(c_flag) \
1604 arm_next_instruction(); \
1605 break; \
1606 \
1607 case 0x4: \
1608 /* MI */ \
1609 if(!n_flag) \
1610 arm_next_instruction(); \
1611 break; \
1612 \
1613 case 0x5: \
1614 /* PL */ \
1615 if(n_flag) \
1616 arm_next_instruction(); \
1617 break; \
1618 \
1619 case 0x6: \
1620 /* VS */ \
1621 if(!v_flag) \
1622 arm_next_instruction(); \
1623 break; \
1624 \
1625 case 0x7: \
1626 /* VC */ \
1627 if(v_flag) \
1628 arm_next_instruction(); \
1629 break; \
1630 \
1631 case 0x8: \
1632 /* HI */ \
1633 if((c_flag == 0) | z_flag) \
1634 arm_next_instruction(); \
1635 break; \
1636 \
1637 case 0x9: \
1638 /* LS */ \
1639 if(c_flag & (z_flag ^ 1)) \
1640 arm_next_instruction(); \
1641 break; \
1642 \
1643 case 0xA: \
1644 /* GE */ \
1645 if(n_flag != v_flag) \
1646 arm_next_instruction(); \
1647 break; \
1648 \
1649 case 0xB: \
1650 /* LT */ \
1651 if(n_flag == v_flag) \
1652 arm_next_instruction(); \
1653 break; \
1654 \
1655 case 0xC: \
1656 /* GT */ \
1657 if(z_flag | (n_flag != v_flag)) \
1658 arm_next_instruction(); \
1659 break; \
1660 \
1661 case 0xD: \
1662 /* LE */ \
1663 if((z_flag == 0) & (n_flag == v_flag)) \
1664 arm_next_instruction(); \
1665 break; \
1666 \
1667 case 0xE: \
1668 /* AL */ \
1669 break; \
1670 \
1671 case 0xF: \
1672 /* Reserved - treat as "never" */ \
1673 quit(); \
1674 arm_next_instruction(); \
1675 break; \
1676 } \
1677 \
1678 switch((opcode >> 20) & 0xFF) \
1679 { \
1680 case 0x00: \
1681 if((opcode & 0x90) == 0x90) \
1682 { \
1683 if(opcode & 0x20) \
1684 { \
1685 /* STRH rd, [rn], -rm */ \
1686 arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); \
1687 } \
1688 else \
1689 { \
1690 /* MUL rd, rm, rs */ \
1691 arm_multiply(no_op, no); \
1692 } \
1693 } \
1694 else \
1695 { \
1696 /* AND rd, rn, reg_op */ \
1697 arm_data_proc(reg[rn] & reg_sh, reg); \
1698 } \
1699 break; \
1700 \
1701 case 0x01: \
1702 if((opcode & 0x90) == 0x90) \
1703 { \
1704 switch((opcode >> 5) & 0x03) \
1705 { \
1706 case 0: \
1707 /* MULS rd, rm, rs */ \
1708 arm_multiply(no_op, yes); \
1709 break; \
1710 \
1711 case 1: \
1712 /* LDRH rd, [rn], -rm */ \
1713 arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); \
1714 break; \
1715 \
1716 case 2: \
1717 /* LDRSB rd, [rn], -rm */ \
1718 arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); \
1719 break; \
1720 \
1721 case 3: \
1722 /* LDRSH rd, [rn], -rm */ \
1723 arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); \
1724 break; \
1725 } \
1726 } \
1727 else \
1728 { \
1729 /* ANDS rd, rn, reg_op */ \
1730 arm_data_proc_logic_flags(reg[rn] & reg_sh, reg); \
1731 } \
1732 break; \
1733 \
1734 case 0x02: \
1735 if((opcode & 0x90) == 0x90) \
1736 { \
1737 if(opcode & 0x20) \
1738 { \
1739 /* STRH rd, [rn], -rm */ \
1740 arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); \
1741 } \
1742 else \
1743 { \
1744 /* MLA rd, rm, rs, rn */ \
1745 arm_multiply(+ reg[rn], no); \
1746 } \
1747 } \
1748 else \
1749 { \
1750 /* EOR rd, rn, reg_op */ \
1751 arm_data_proc(reg[rn] ^ reg_sh, reg); \
1752 } \
1753 break; \
1754 \
1755 case 0x03: \
1756 if((opcode & 0x90) == 0x90) \
1757 { \
1758 switch((opcode >> 5) & 0x03) \
1759 { \
1760 case 0: \
1761 /* MLAS rd, rm, rs, rn */ \
1762 arm_multiply(+ reg[rn], yes); \
1763 break; \
1764 \
1765 case 1: \
1766 /* LDRH rd, [rn], -rm */ \
1767 arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); \
1768 break; \
1769 \
1770 case 2: \
1771 /* LDRSB rd, [rn], -rm */ \
1772 arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); \
1773 break; \
1774 \
1775 case 3: \
1776 /* LDRSH rd, [rn], -rm */ \
1777 arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); \
1778 break; \
1779 } \
1780 } \
1781 else \
1782 { \
1783 /* EORS rd, rn, reg_op */ \
1784 arm_data_proc_logic_flags(reg[rn] ^ reg_sh, reg); \
1785 } \
1786 break; \
1787 \
1788 case 0x04: \
1789 if((opcode & 0x90) == 0x90) \
1790 { \
1791 /* STRH rd, [rn], -imm */ \
1792 arm_access_memory(store, no_op, half_imm, u16, yes, - offset); \
1793 } \
1794 else \
1795 { \
1796 /* SUB rd, rn, reg_op */ \
1797 arm_data_proc(reg[rn] - reg_sh, reg); \
1798 } \
1799 break; \
1800 \
1801 case 0x05: \
1802 if((opcode & 0x90) == 0x90) \
1803 { \
1804 switch((opcode >> 5) & 0x03) \
1805 { \
1806 case 1: \
1807 /* LDRH rd, [rn], -imm */ \
1808 arm_access_memory(load, no_op, half_imm, u16, yes, - offset); \
1809 break; \
1810 \
1811 case 2: \
1812 /* LDRSB rd, [rn], -imm */ \
1813 arm_access_memory(load, no_op, half_imm, s8, yes, - offset); \
1814 break; \
1815 \
1816 case 3: \
1817 /* LDRSH rd, [rn], -imm */ \
1818 arm_access_memory(load, no_op, half_imm, s16, yes, - offset); \
1819 break; \
1820 } \
1821 } \
1822 else \
1823 { \
1824 /* SUBS rd, rn, reg_op */ \
1825 arm_data_proc_sub_flags(reg[rn], reg_sh, reg); \
1826 } \
1827 break; \
1828 \
1829 case 0x06: \
1830 if((opcode & 0x90) == 0x90) \
1831 { \
1832 /* STRH rd, [rn], -imm */ \
1833 arm_access_memory(store, no_op, half_imm, u16, yes, - offset); \
1834 } \
1835 else \
1836 { \
1837 /* RSB rd, rn, reg_op */ \
1838 arm_data_proc(reg_sh - reg[rn], reg); \
1839 } \
1840 break; \
1841 \
1842 case 0x07: \
1843 if((opcode & 0x90) == 0x90) \
1844 { \
1845 switch((opcode >> 5) & 0x03) \
1846 { \
1847 case 1: \
1848 /* LDRH rd, [rn], -imm */ \
1849 arm_access_memory(load, no_op, half_imm, u16, yes, - offset); \
1850 break; \
1851 \
1852 case 2: \
1853 /* LDRSB rd, [rn], -imm */ \
1854 arm_access_memory(load, no_op, half_imm, s8, yes, - offset); \
1855 break; \
1856 \
1857 case 3: \
1858 /* LDRSH rd, [rn], -imm */ \
1859 arm_access_memory(load, no_op, half_imm, s16, yes, - offset); \
1860 break; \
1861 } \
1862 } \
1863 else \
1864 { \
1865 /* RSBS rd, rn, reg_op */ \
1866 arm_data_proc_sub_flags(reg_sh, reg[rn], reg); \
1867 } \
1868 break; \
1869 \
1870 case 0x08: \
1871 if((opcode & 0x90) == 0x90) \
1872 { \
1873 if(opcode & 0x20) \
1874 { \
1875 /* STRH rd, [rn], +rm */ \
1876 arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); \
1877 } \
1878 else \
1879 { \
1880 /* UMULL rd, rm, rs */ \
1881 arm_multiply_long(no_op, no, u); \
1882 } \
1883 } \
1884 else \
1885 { \
1886 /* ADD rd, rn, reg_op */ \
1887 arm_data_proc(reg[rn] + reg_sh, reg); \
1888 } \
1889 break; \
1890 \
1891 case 0x09: \
1892 if((opcode & 0x90) == 0x90) \
1893 { \
1894 switch((opcode >> 5) & 0x03) \
1895 { \
1896 case 0: \
1897 /* UMULLS rdlo, rdhi, rm, rs */ \
1898 arm_multiply_long(no_op, yes, u); \
1899 break; \
1900 \
1901 case 1: \
1902 /* LDRH rd, [rn], +rm */ \
1903 arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); \
1904 break; \
1905 \
1906 case 2: \
1907 /* LDRSB rd, [rn], +rm */ \
1908 arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); \
1909 break; \
1910 \
1911 case 3: \
1912 /* LDRSH rd, [rn], +rm */ \
1913 arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); \
1914 break; \
1915 } \
1916 } \
1917 else \
1918 { \
1919 /* ADDS rd, rn, reg_op */ \
1920 arm_data_proc_add_flags(reg[rn], reg_sh, reg); \
1921 } \
1922 break; \
1923 \
1924 case 0x0A: \
1925 if((opcode & 0x90) == 0x90) \
1926 { \
1927 if(opcode & 0x20) \
1928 { \
1929 /* STRH rd, [rn], +rm */ \
1930 arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); \
1931 } \
1932 else \
1933 { \
1934 /* UMLAL rd, rm, rs */ \
1935 arm_multiply_long(arm_multiply_long_addop(u), no, u); \
1936 } \
1937 } \
1938 else \
1939 { \
1940 /* ADC rd, rn, reg_op */ \
1941 arm_data_proc(reg[rn] + reg_sh + c_flag, reg); \
1942 } \
1943 break; \
1944 \
1945 case 0x0B: \
1946 if((opcode & 0x90) == 0x90) \
1947 { \
1948 switch((opcode >> 5) & 0x03) \
1949 { \
1950 case 0: \
1951 /* UMLALS rdlo, rdhi, rm, rs */ \
1952 arm_multiply_long(arm_multiply_long_addop(u), yes, u); \
1953 break; \
1954 \
1955 case 1: \
1956 /* LDRH rd, [rn], +rm */ \
1957 arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); \
1958 break; \
1959 \
1960 case 2: \
1961 /* LDRSB rd, [rn], +rm */ \
1962 arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); \
1963 break; \
1964 \
1965 case 3: \
1966 /* LDRSH rd, [rn], +rm */ \
1967 arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); \
1968 break; \
1969 } \
1970 } \
1971 else \
1972 { \
1973 /* ADCS rd, rn, reg_op */ \
1974 arm_data_proc_add_flags(reg[rn], reg_sh + c_flag, reg); \
1975 } \
1976 break; \
1977 \
1978 case 0x0C: \
1979 if((opcode & 0x90) == 0x90) \
1980 { \
1981 if(opcode & 0x20) \
1982 { \
1983 /* STRH rd, [rn], +imm */ \
1984 arm_access_memory(store, no_op, half_imm, u16, yes, + offset); \
1985 } \
1986 else \
1987 { \
1988 /* SMULL rd, rm, rs */ \
1989 arm_multiply_long(no_op, no, s); \
1990 } \
1991 } \
1992 else \
1993 { \
1994 /* SBC rd, rn, reg_op */ \
1995 arm_data_proc(reg[rn] - (reg_sh + (c_flag ^ 1)), reg); \
1996 } \
1997 break; \
1998 \
1999 case 0x0D: \
2000 if((opcode & 0x90) == 0x90) \
2001 { \
2002 switch((opcode >> 5) & 0x03) \
2003 { \
2004 case 0: \
2005 /* SMULLS rdlo, rdhi, rm, rs */ \
2006 arm_multiply_long(no_op, yes, s); \
2007 break; \
2008 \
2009 case 1: \
2010 /* LDRH rd, [rn], +imm */ \
2011 arm_access_memory(load, no_op, half_imm, u16, yes, + offset); \
2012 break; \
2013 \
2014 case 2: \
2015 /* LDRSB rd, [rn], +imm */ \
2016 arm_access_memory(load, no_op, half_imm, s8, yes, + offset); \
2017 break; \
2018 \
2019 case 3: \
2020 /* LDRSH rd, [rn], +imm */ \
2021 arm_access_memory(load, no_op, half_imm, s16, yes, + offset); \
2022 break; \
2023 } \
2024 } \
2025 else \
2026 { \
2027 /* SBCS rd, rn, reg_op */ \
2028 arm_data_proc_sub_flags(reg[rn], (reg_sh + (c_flag ^ 1)), reg); \
2029 } \
2030 break; \
2031 \
2032 case 0x0E: \
2033 if((opcode & 0x90) == 0x90) \
2034 { \
2035 if(opcode & 0x20) \
2036 { \
2037 /* STRH rd, [rn], +imm */ \
2038 arm_access_memory(store, no_op, half_imm, u16, yes, + offset); \
2039 } \
2040 else \
2041 { \
2042 /* SMLAL rd, rm, rs */ \
2043 arm_multiply_long(arm_multiply_long_addop(s), no, s); \
2044 } \
2045 } \
2046 else \
2047 { \
2048 /* RSC rd, rn, reg_op */ \
2049 arm_data_proc(reg_sh - reg[rn] + c_flag - 1, reg); \
2050 } \
2051 break; \
2052 \
2053 case 0x0F: \
2054 if((opcode & 0x90) == 0x90) \
2055 { \
2056 switch((opcode >> 5) & 0x03) \
2057 { \
2058 case 0: \
2059 /* SMLALS rdlo, rdhi, rm, rs */ \
2060 arm_multiply_long(arm_multiply_long_addop(s), yes, s); \
2061 break; \
2062 \
2063 case 1: \
2064 /* LDRH rd, [rn], +imm */ \
2065 arm_access_memory(load, no_op, half_imm, u16, yes, + offset); \
2066 break; \
2067 \
2068 case 2: \
2069 /* LDRSB rd, [rn], +imm */ \
2070 arm_access_memory(load, no_op, half_imm, s8, yes, + offset); \
2071 break; \
2072 \
2073 case 3: \
2074 /* LDRSH rd, [rn], +imm */ \
2075 arm_access_memory(load, no_op, half_imm, s16, yes, + offset); \
2076 break; \
2077 } \
2078 } \
2079 else \
2080 { \
2081 /* RSCS rd, rn, reg_op */ \
2082 arm_data_proc_sub_flags((reg_sh + c_flag - 1), reg[rn], reg); \
2083 } \
2084 break; \
2085 \
2086 case 0x10: \
2087 if((opcode & 0x90) == 0x90) \
2088 { \
2089 if(opcode & 0x20) \
2090 { \
2091 /* STRH rd, [rn - rm] */ \
2092 arm_access_memory(store, - reg[rm], half_reg, u16, no, no_op); \
2093 } \
2094 else \
2095 { \
2096 /* SWP rd, rm, [rn] */ \
2097 arm_swap(u32); \
2098 } \
2099 } \
2100 else \
2101 { \
2102 /* MRS rd, cpsr */ \
2103 arm_psr(reg, read, reg[REG_CPSR]); \
2104 } \
2105 break; \
2106 \
2107 case 0x11: \
2108 if((opcode & 0x90) == 0x90) \
2109 { \
2110 switch((opcode >> 5) & 0x03) \
2111 { \
2112 case 1: \
2113 /* LDRH rd, [rn - rm] */ \
2114 arm_access_memory(load, - reg[rm], half_reg, u16, no, no_op); \
2115 break; \
2116 \
2117 case 2: \
2118 /* LDRSB rd, [rn - rm] */ \
2119 arm_access_memory(load, - reg[rm], half_reg, s8, no, no_op); \
2120 break; \
2121 \
2122 case 3: \
2123 /* LDRSH rd, [rn - rm] */ \
2124 arm_access_memory(load, - reg[rm], half_reg, s16, no, no_op); \
2125 break; \
2126 } \
2127 } \
2128 else \
2129 { \
2130 /* TST rd, rn, reg_op */ \
2131 arm_data_proc_test_logic(reg[rn] & reg_sh, reg); \
2132 } \
2133 break; \
2134 \
2135 case 0x12: \
2136 if((opcode & 0x90) == 0x90) \
2137 { \
2138 /* STRH rd, [rn - rm]! */ \
2139 arm_access_memory(store, - reg[rm], half_reg, u16, yes, no_op); \
2140 } \
2141 else \
2142 { \
2143 if(opcode & 0x10) \
2144 { \
2145 /* BX rn */ \
2146 arm_decode_branchx(); \
2147 u32 src = reg[rn]; \
2148 if(src & 0x01) \
2149 { \
2150 src -= 1; \
2151 arm_pc_offset_update_direct(src); \
2152 reg[REG_CPSR] |= 0x20; \
2153 goto thumb_loop; \
2154 } \
2155 else \
2156 { \
2157 arm_pc_offset_update_direct(src); \
2158 } \
2159 } \
2160 else \
2161 { \
2162 /* MSR cpsr, rm */ \
2163 arm_psr(reg, store, cpsr); \
2164 } \
2165 } \
2166 break; \
2167 \
2168 case 0x13: \
2169 if((opcode & 0x90) == 0x90) \
2170 { \
2171 switch((opcode >> 5) & 0x03) \
2172 { \
2173 case 1: \
2174 /* LDRH rd, [rn - rm]! */ \
2175 arm_access_memory(load, - reg[rm], half_reg, u16, yes, no_op); \
2176 break; \
2177 \
2178 case 2: \
2179 /* LDRSB rd, [rn - rm]! */ \
2180 arm_access_memory(load, - reg[rm], half_reg, s8, yes, no_op); \
2181 break; \
2182 \
2183 case 3: \
2184 /* LDRSH rd, [rn - rm]! */ \
2185 arm_access_memory(load, - reg[rm], half_reg, s16, yes, no_op); \
2186 break; \
2187 } \
2188 } \
2189 else \
2190 { \
2191 /* TEQ rd, rn, reg_op */ \
2192 arm_data_proc_test_logic(reg[rn] ^ reg_sh, reg); \
2193 } \
2194 break; \
2195 \
2196 case 0x14: \
2197 if((opcode & 0x90) == 0x90) \
2198 { \
2199 if(opcode & 0x20) \
2200 { \
2201 /* STRH rd, [rn - imm] */ \
2202 arm_access_memory(store, - offset, half_imm, u16, no, no_op); \
2203 } \
2204 else \
2205 { \
2206 /* SWPB rd, rm, [rn] */ \
2207 arm_swap(u8); \
2208 } \
2209 } \
2210 else \
2211 { \
2212 /* MRS rd, spsr */ \
2213 arm_psr(reg, read, spsr[reg[CPU_MODE]]); \
2214 } \
2215 break; \
2216 \
2217 case 0x15: \
2218 if((opcode & 0x90) == 0x90) \
2219 { \
2220 switch((opcode >> 5) & 0x03) \
2221 { \
2222 case 1: \
2223 /* LDRH rd, [rn - imm] */ \
2224 arm_access_memory(load, - offset, half_imm, u16, no, no_op); \
2225 break; \
2226 \
2227 case 2: \
2228 /* LDRSB rd, [rn - imm] */ \
2229 arm_access_memory(load, - offset, half_imm, s8, no, no_op); \
2230 break; \
2231 \
2232 case 3: \
2233 /* LDRSH rd, [rn - imm] */ \
2234 arm_access_memory(load, - offset, half_imm, s16, no, no_op); \
2235 break; \
2236 } \
2237 } \
2238 else \
2239 { \
2240 /* CMP rn, reg_op */ \
2241 arm_data_proc_test_sub(reg[rn], reg_sh, reg); \
2242 } \
2243 break; \
2244 \
2245 case 0x16: \
2246 if((opcode & 0x90) == 0x90) \
2247 { \
2248 /* STRH rd, [rn - imm]! */ \
2249 arm_access_memory(store, - offset, half_imm, u16, yes, no_op); \
2250 } \
2251 else \
2252 { \
2253 /* MSR spsr, rm */ \
2254 arm_psr(reg, store, spsr); \
2255 } \
2256 break; \
2257 \
2258 case 0x17: \
2259 if((opcode & 0x90) == 0x90) \
2260 { \
2261 switch((opcode >> 5) & 0x03) \
2262 { \
2263 case 1: \
2264 /* LDRH rd, [rn - imm]! */ \
2265 arm_access_memory(load, - offset, half_imm, u16, yes, no_op); \
2266 break; \
2267 \
2268 case 2: \
2269 /* LDRSB rd, [rn - imm]! */ \
2270 arm_access_memory(load, - offset, half_imm, s8, yes, no_op); \
2271 break; \
2272 \
2273 case 3: \
2274 /* LDRSH rd, [rn - imm]! */ \
2275 arm_access_memory(load, - offset, half_imm, s16, yes, no_op); \
2276 break; \
2277 } \
2278 } \
2279 else \
2280 { \
2281 /* CMN rd, rn, reg_op */ \
2282 arm_data_proc_test_add(reg[rn], reg_sh, reg); \
2283 } \
2284 break; \
2285 \
2286 case 0x18: \
2287 if((opcode & 0x90) == 0x90) \
2288 { \
2289 /* STRH rd, [rn + rm] */ \
2290 arm_access_memory(store, + reg[rm], half_reg, u16, no, no_op); \
2291 } \
2292 else \
2293 { \
2294 /* ORR rd, rn, reg_op */ \
2295 arm_data_proc(reg[rn] | reg_sh, reg); \
2296 } \
2297 break; \
2298 \
2299 case 0x19: \
2300 if((opcode & 0x90) == 0x90) \
2301 { \
2302 switch((opcode >> 5) & 0x03) \
2303 { \
2304 case 1: \
2305 /* LDRH rd, [rn + rm] */ \
2306 arm_access_memory(load, + reg[rm], half_reg, u16, no, no_op); \
2307 break; \
2308 \
2309 case 2: \
2310 /* LDRSB rd, [rn + rm] */ \
2311 arm_access_memory(load, + reg[rm], half_reg, s8, no, no_op); \
2312 break; \
2313 \
2314 case 3: \
2315 /* LDRSH rd, [rn + rm] */ \
2316 arm_access_memory(load, + reg[rm], half_reg, s16, no, no_op); \
2317 break; \
2318 } \
2319 } \
2320 else \
2321 { \
2322 /* ORRS rd, rn, reg_op */ \
2323 arm_data_proc_logic_flags(reg[rn] | reg_sh, reg); \
2324 } \
2325 break; \
2326 \
2327 case 0x1A: \
2328 if((opcode & 0x90) == 0x90) \
2329 { \
2330 /* STRH rd, [rn + rm]! */ \
2331 arm_access_memory(store, + reg[rm], half_reg, u16, yes, no_op); \
2332 } \
2333 else \
2334 { \
2335 /* MOV rd, reg_op */ \
2336 arm_data_proc(reg_sh, reg); \
2337 } \
2338 break; \
2339 \
2340 case 0x1B: \
2341 if((opcode & 0x90) == 0x90) \
2342 { \
2343 switch((opcode >> 5) & 0x03) \
2344 { \
2345 case 1: \
2346 /* LDRH rd, [rn + rm]! */ \
2347 arm_access_memory(load, + reg[rm], half_reg, u16, yes, no_op); \
2348 break; \
2349 \
2350 case 2: \
2351 /* LDRSB rd, [rn + rm]! */ \
2352 arm_access_memory(load, + reg[rm], half_reg, s8, yes, no_op); \
2353 break; \
2354 \
2355 case 3: \
2356 /* LDRSH rd, [rn + rm]! */ \
2357 arm_access_memory(load, + reg[rm], half_reg, s16, yes, no_op); \
2358 break; \
2359 } \
2360 } \
2361 else \
2362 { \
2363 /* MOVS rd, reg_op */ \
2364 arm_data_proc_logic_flags(reg_sh, reg); \
2365 } \
2366 break; \
2367 \
2368 case 0x1C: \
2369 if((opcode & 0x90) == 0x90) \
2370 { \
2371 /* STRH rd, [rn + imm] */ \
2372 arm_access_memory(store, + offset, half_imm, u16, no, no_op); \
2373 } \
2374 else \
2375 { \
2376 /* BIC rd, rn, reg_op */ \
2377 arm_data_proc(reg[rn] & (~reg_sh), reg); \
2378 } \
2379 break; \
2380 \
2381 case 0x1D: \
2382 if((opcode & 0x90) == 0x90) \
2383 { \
2384 switch((opcode >> 5) & 0x03) \
2385 { \
2386 case 1: \
2387 /* LDRH rd, [rn + imm] */ \
2388 arm_access_memory(load, + offset, half_imm, u16, no, no_op); \
2389 break; \
2390 \
2391 case 2: \
2392 /* LDRSB rd, [rn + imm] */ \
2393 arm_access_memory(load, + offset, half_imm, s8, no, no_op); \
2394 break; \
2395 \
2396 case 3: \
2397 /* LDRSH rd, [rn + imm] */ \
2398 arm_access_memory(load, + offset, half_imm, s16, no, no_op); \
2399 break; \
2400 } \
2401 } \
2402 else \
2403 { \
2404 /* BICS rd, rn, reg_op */ \
2405 arm_data_proc_logic_flags(reg[rn] & (~reg_sh), reg); \
2406 } \
2407 break; \
2408 \
2409 case 0x1E: \
2410 if((opcode & 0x90) == 0x90) \
2411 { \
2412 /* STRH rd, [rn + imm]! */ \
2413 arm_access_memory(store, + offset, half_imm, u16, yes, no_op); \
2414 } \
2415 else \
2416 { \
2417 /* MVN rd, reg_op */ \
2418 arm_data_proc(~reg_sh, reg); \
2419 } \
2420 break; \
2421 \
2422 case 0x1F: \
2423 if((opcode & 0x90) == 0x90) \
2424 { \
2425 switch((opcode >> 5) & 0x03) \
2426 { \
2427 case 1: \
2428 /* LDRH rd, [rn + imm]! */ \
2429 arm_access_memory(load, + offset, half_imm, u16, yes, no_op); \
2430 break; \
2431 \
2432 case 2: \
2433 /* LDRSB rd, [rn + imm]! */ \
2434 arm_access_memory(load, + offset, half_imm, s8, yes, no_op); \
2435 break; \
2436 \
2437 case 3: \
2438 /* LDRSH rd, [rn + imm]! */ \
2439 arm_access_memory(load, + offset, half_imm, s16, yes, no_op); \
2440 break; \
2441 } \
2442 } \
2443 else \
2444 { \
2445 /* MVNS rd, rn, reg_op */ \
2446 arm_data_proc_logic_flags(~reg_sh, reg); \
2447 } \
2448 break; \
2449 \
2450 case 0x20: \
2451 /* AND rd, rn, imm */ \
2452 arm_data_proc(reg[rn] & imm, imm); \
2453 break; \
2454 \
2455 case 0x21: \
2456 /* ANDS rd, rn, imm */ \
2457 arm_data_proc_logic_flags(reg[rn] & imm, imm); \
2458 break; \
2459 \
2460 case 0x22: \
2461 /* EOR rd, rn, imm */ \
2462 arm_data_proc(reg[rn] ^ imm, imm); \
2463 break; \
2464 \
2465 case 0x23: \
2466 /* EORS rd, rn, imm */ \
2467 arm_data_proc_logic_flags(reg[rn] ^ imm, imm); \
2468 break; \
2469 \
2470 case 0x24: \
2471 /* SUB rd, rn, imm */ \
2472 arm_data_proc(reg[rn] - imm, imm); \
2473 break; \
2474 \
2475 case 0x25: \
2476 /* SUBS rd, rn, imm */ \
2477 arm_data_proc_sub_flags(reg[rn], imm, imm); \
2478 break; \
2479 \
2480 case 0x26: \
2481 /* RSB rd, rn, imm */ \
2482 arm_data_proc(imm - reg[rn], imm); \
2483 break; \
2484 \
2485 case 0x27: \
2486 /* RSBS rd, rn, imm */ \
2487 arm_data_proc_sub_flags(imm, reg[rn], imm); \
2488 break; \
2489 \
2490 case 0x28: \
2491 /* ADD rd, rn, imm */ \
2492 arm_data_proc(reg[rn] + imm, imm); \
2493 break; \
2494 \
2495 case 0x29: \
2496 /* ADDS rd, rn, imm */ \
2497 arm_data_proc_add_flags(reg[rn], imm, imm); \
2498 break; \
2499 \
2500 case 0x2A: \
2501 /* ADC rd, rn, imm */ \
2502 arm_data_proc(reg[rn] + imm + c_flag, imm); \
2503 break; \
2504 \
2505 case 0x2B: \
2506 /* ADCS rd, rn, imm */ \
2507 arm_data_proc_add_flags(reg[rn] + imm, c_flag, imm); \
2508 break; \
2509 \
2510 case 0x2C: \
2511 /* SBC rd, rn, imm */ \
2512 arm_data_proc(reg[rn] - imm + c_flag - 1, imm); \
2513 break; \
2514 \
2515 case 0x2D: \
2516 /* SBCS rd, rn, imm */ \
2517 arm_data_proc_sub_flags(reg[rn], (imm + (c_flag ^ 1)), imm); \
2518 break; \
2519 \
2520 case 0x2E: \
2521 /* RSC rd, rn, imm */ \
2522 arm_data_proc(imm - reg[rn] + c_flag - 1, imm); \
2523 break; \
2524 \
2525 case 0x2F: \
2526 /* RSCS rd, rn, imm */ \
2527 arm_data_proc_sub_flags((imm + c_flag - 1), reg[rn], imm); \
2528 break; \
2529 \
2530 case 0x30 ... 0x31: \
2531 /* TST rn, imm */ \
2532 arm_data_proc_test_logic(reg[rn] & imm, imm); \
2533 break; \
2534 \
2535 case 0x32: \
2536 /* MSR cpsr, imm */ \
2537 arm_psr(imm, store, cpsr); \
2538 break; \
2539 \
2540 case 0x33: \
2541 /* TEQ rn, imm */ \
2542 arm_data_proc_test_logic(reg[rn] ^ imm, imm); \
2543 break; \
2544 \
2545 case 0x34 ... 0x35: \
2546 /* CMP rn, imm */ \
2547 arm_data_proc_test_sub(reg[rn], imm, imm); \
2548 break; \
2549 \
2550 case 0x36: \
2551 /* MSR spsr, imm */ \
2552 arm_psr(imm, store, spsr); \
2553 break; \
2554 \
2555 case 0x37: \
2556 /* CMN rn, imm */ \
2557 arm_data_proc_test_add(reg[rn], imm, imm); \
2558 break; \
2559 \
2560 case 0x38: \
2561 /* ORR rd, rn, imm */ \
2562 arm_data_proc(reg[rn] | imm, imm); \
2563 break; \
2564 \
2565 case 0x39: \
2566 /* ORRS rd, rn, imm */ \
2567 arm_data_proc_logic_flags(reg[rn] | imm, imm); \
2568 break; \
2569 \
2570 case 0x3A: \
2571 /* MOV rd, imm */ \
2572 arm_data_proc(imm, imm); \
2573 break; \
2574 \
2575 case 0x3B: \
2576 /* MOVS rd, imm */ \
2577 arm_data_proc_logic_flags(imm, imm); \
2578 break; \
2579 \
2580 case 0x3C: \
2581 /* BIC rd, rn, imm */ \
2582 arm_data_proc(reg[rn] & (~imm), imm); \
2583 break; \
2584 \
2585 case 0x3D: \
2586 /* BICS rd, rn, imm */ \
2587 arm_data_proc_logic_flags(reg[rn] & (~imm), imm); \
2588 break; \
2589 \
2590 case 0x3E: \
2591 /* MVN rd, imm */ \
2592 arm_data_proc(~imm, imm); \
2593 break; \
2594 \
2595 case 0x3F: \
2596 /* MVNS rd, imm */ \
2597 arm_data_proc_logic_flags(~imm, imm); \
2598 break; \
2599 \
2600 case 0x40: \
2601 /* STR rd, [rn], -imm */ \
2602 arm_access_memory(store, no_op, imm, u32, yes, - offset); \
2603 break; \
2604 \
2605 case 0x41: \
2606 /* LDR rd, [rn], -imm */ \
2607 arm_access_memory(load, no_op, imm, u32, yes, - offset); \
2608 break; \
2609 \
2610 case 0x42: \
2611 /* STRT rd, [rn], -imm */ \
2612 arm_access_memory(store, no_op, imm, u32, yes, - offset); \
2613 break; \
2614 \
2615 case 0x43: \
2616 /* LDRT rd, [rn], -imm */ \
2617 arm_access_memory(load, no_op, imm, u32, yes, - offset); \
2618 break; \
2619 \
2620 case 0x44: \
2621 /* STRB rd, [rn], -imm */ \
2622 arm_access_memory(store, no_op, imm, u8, yes, - offset); \
2623 break; \
2624 \
2625 case 0x45: \
2626 /* LDRB rd, [rn], -imm */ \
2627 arm_access_memory(load, no_op, imm, u8, yes, - offset); \
2628 break; \
2629 \
2630 case 0x46: \
2631 /* STRBT rd, [rn], -imm */ \
2632 arm_access_memory(store, no_op, imm, u8, yes, - offset); \
2633 break; \
2634 \
2635 case 0x47: \
2636 /* LDRBT rd, [rn], -imm */ \
2637 arm_access_memory(load, no_op, imm, u8, yes, - offset); \
2638 break; \
2639 \
2640 case 0x48: \
2641 /* STR rd, [rn], +imm */ \
2642 arm_access_memory(store, no_op, imm, u32, yes, + offset); \
2643 break; \
2644 \
2645 case 0x49: \
2646 /* LDR rd, [rn], +imm */ \
2647 arm_access_memory(load, no_op, imm, u32, yes, + offset); \
2648 break; \
2649 \
2650 case 0x4A: \
2651 /* STRT rd, [rn], +imm */ \
2652 arm_access_memory(store, no_op, imm, u32, yes, + offset); \
2653 break; \
2654 \
2655 case 0x4B: \
2656 /* LDRT rd, [rn], +imm */ \
2657 arm_access_memory(load, no_op, imm, u32, yes, + offset); \
2658 break; \
2659 \
2660 case 0x4C: \
2661 /* STRB rd, [rn], +imm */ \
2662 arm_access_memory(store, no_op, imm, u8, yes, + offset); \
2663 break; \
2664 \
2665 case 0x4D: \
2666 /* LDRB rd, [rn], +imm */ \
2667 arm_access_memory(load, no_op, imm, u8, yes, + offset); \
2668 break; \
2669 \
2670 case 0x4E: \
2671 /* STRBT rd, [rn], +imm */ \
2672 arm_access_memory(store, no_op, imm, u8, yes, + offset); \
2673 break; \
2674 \
2675 case 0x4F: \
2676 /* LDRBT rd, [rn], +imm */ \
2677 arm_access_memory(load, no_op, imm, u8, yes, + offset); \
2678 break; \
2679 \
2680 case 0x50: \
2681 /* STR rd, [rn - imm] */ \
2682 arm_access_memory(store, - offset, imm, u32, no, no_op); \
2683 break; \
2684 \
2685 case 0x51: \
2686 /* LDR rd, [rn - imm] */ \
2687 arm_access_memory(load, - offset, imm, u32, no, no_op); \
2688 break; \
2689 \
2690 case 0x52: \
2691 /* STR rd, [rn - imm]! */ \
2692 arm_access_memory(store, - offset, imm, u32, yes, no_op); \
2693 break; \
2694 \
2695 case 0x53: \
2696 /* LDR rd, [rn - imm]! */ \
2697 arm_access_memory(load, - offset, imm, u32, yes, no_op); \
2698 break; \
2699 \
2700 case 0x54: \
2701 /* STRB rd, [rn - imm] */ \
2702 arm_access_memory(store, - offset, imm, u8, no, no_op); \
2703 break; \
2704 \
2705 case 0x55: \
2706 /* LDRB rd, [rn - imm] */ \
2707 arm_access_memory(load, - offset, imm, u8, no, no_op); \
2708 break; \
2709 \
2710 case 0x56: \
2711 /* STRB rd, [rn - imm]! */ \
2712 arm_access_memory(store, - offset, imm, u8, yes, no_op); \
2713 break; \
2714 \
2715 case 0x57: \
2716 /* LDRB rd, [rn - imm]! */ \
2717 arm_access_memory(load, - offset, imm, u8, yes, no_op); \
2718 break; \
2719 \
2720 case 0x58: \
2721 /* STR rd, [rn + imm] */ \
2722 arm_access_memory(store, + offset, imm, u32, no, no_op); \
2723 break; \
2724 \
2725 case 0x59: \
2726 /* LDR rd, [rn + imm] */ \
2727 arm_access_memory(load, + offset, imm, u32, no, no_op); \
2728 break; \
2729 \
2730 case 0x5A: \
2731 /* STR rd, [rn + imm]! */ \
2732 arm_access_memory(store, + offset, imm, u32, yes, no_op); \
2733 break; \
2734 \
2735 case 0x5B: \
2736 /* LDR rd, [rn + imm]! */ \
2737 arm_access_memory(load, + offset, imm, u32, yes, no_op); \
2738 break; \
2739 \
2740 case 0x5C: \
2741 /* STRB rd, [rn + imm] */ \
2742 arm_access_memory(store, + offset, imm, u8, no, no_op); \
2743 break; \
2744 \
2745 case 0x5D: \
2746 /* LDRB rd, [rn + imm] */ \
2747 arm_access_memory(load, + offset, imm, u8, no, no_op); \
2748 break; \
2749 \
2750 case 0x5E: \
2751 /* STRB rd, [rn + imm]! */ \
2752 arm_access_memory(store, + offset, imm, u8, yes, no_op); \
2753 break; \
2754 \
2755 case 0x5F: \
2756 /* LDRBT rd, [rn + imm]! */ \
2757 arm_access_memory(load, + offset, imm, u8, yes, no_op); \
2758 break; \
2759 \
2760 case 0x60: \
2761 /* STR rd, [rn], -reg_op */ \
2762 arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); \
2763 break; \
2764 \
2765 case 0x61: \
2766 /* LDR rd, [rn], -reg_op */ \
2767 arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); \
2768 break; \
2769 \
2770 case 0x62: \
2771 /* STRT rd, [rn], -reg_op */ \
2772 arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); \
2773 break; \
2774 \
2775 case 0x63: \
2776 /* LDRT rd, [rn], -reg_op */ \
2777 arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); \
2778 break; \
2779 \
2780 case 0x64: \
2781 /* STRB rd, [rn], -reg_op */ \
2782 arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); \
2783 break; \
2784 \
2785 case 0x65: \
2786 /* LDRB rd, [rn], -reg_op */ \
2787 arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); \
2788 break; \
2789 \
2790 case 0x66: \
2791 /* STRBT rd, [rn], -reg_op */ \
2792 arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); \
2793 break; \
2794 \
2795 case 0x67: \
2796 /* LDRBT rd, [rn], -reg_op */ \
2797 arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); \
2798 break; \
2799 \
2800 case 0x68: \
2801 /* STR rd, [rn], +reg_op */ \
2802 arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); \
2803 break; \
2804 \
2805 case 0x69: \
2806 /* LDR rd, [rn], +reg_op */ \
2807 arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); \
2808 break; \
2809 \
2810 case 0x6A: \
2811 /* STRT rd, [rn], +reg_op */ \
2812 arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); \
2813 break; \
2814 \
2815 case 0x6B: \
2816 /* LDRT rd, [rn], +reg_op */ \
2817 arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); \
2818 break; \
2819 \
2820 case 0x6C: \
2821 /* STRB rd, [rn], +reg_op */ \
2822 arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); \
2823 break; \
2824 \
2825 case 0x6D: \
2826 /* LDRB rd, [rn], +reg_op */ \
2827 arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); \
2828 break; \
2829 \
2830 case 0x6E: \
2831 /* STRBT rd, [rn], +reg_op */ \
2832 arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); \
2833 break; \
2834 \
2835 case 0x6F: \
2836 /* LDRBT rd, [rn], +reg_op */ \
2837 arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); \
2838 break; \
2839 \
2840 case 0x70: \
2841 /* STR rd, [rn - reg_op] */ \
2842 arm_access_memory(store, - reg_offset, reg, u32, no, no_op); \
2843 break; \
2844 \
2845 case 0x71: \
2846 /* LDR rd, [rn - reg_op] */ \
2847 arm_access_memory(load, - reg_offset, reg, u32, no, no_op); \
2848 break; \
2849 \
2850 case 0x72: \
2851 /* STR rd, [rn - reg_op]! */ \
2852 arm_access_memory(store, - reg_offset, reg, u32, yes, no_op); \
2853 break; \
2854 \
2855 case 0x73: \
2856 /* LDR rd, [rn - reg_op]! */ \
2857 arm_access_memory(load, - reg_offset, reg, u32, yes, no_op); \
2858 break; \
2859 \
2860 case 0x74: \
2861 /* STRB rd, [rn - reg_op] */ \
2862 arm_access_memory(store, - reg_offset, reg, u8, no, no_op); \
2863 break; \
2864 \
2865 case 0x75: \
2866 /* LDRB rd, [rn - reg_op] */ \
2867 arm_access_memory(load, - reg_offset, reg, u8, no, no_op); \
2868 break; \
2869 \
2870 case 0x76: \
2871 /* STRB rd, [rn - reg_op]! */ \
2872 arm_access_memory(store, - reg_offset, reg, u8, yes, no_op); \
2873 break; \
2874 \
2875 case 0x77: \
2876 /* LDRB rd, [rn - reg_op]! */ \
2877 arm_access_memory(load, - reg_offset, reg, u8, yes, no_op); \
2878 break; \
2879 \
2880 case 0x78: \
2881 /* STR rd, [rn + reg_op] */ \
2882 arm_access_memory(store, + reg_offset, reg, u32, no, no_op); \
2883 break; \
2884 \
2885 case 0x79: \
2886 /* LDR rd, [rn + reg_op] */ \
2887 arm_access_memory(load, + reg_offset, reg, u32, no, no_op); \
2888 break; \
2889 \
2890 case 0x7A: \
2891 /* STR rd, [rn + reg_op]! */ \
2892 arm_access_memory(store, + reg_offset, reg, u32, yes, no_op); \
2893 break; \
2894 \
2895 case 0x7B: \
2896 /* LDR rd, [rn + reg_op]! */ \
2897 arm_access_memory(load, + reg_offset, reg, u32, yes, no_op); \
2898 break; \
2899 \
2900 case 0x7C: \
2901 /* STRB rd, [rn + reg_op] */ \
2902 arm_access_memory(store, + reg_offset, reg, u8, no, no_op); \
2903 break; \
2904 \
2905 case 0x7D: \
2906 /* LDRB rd, [rn + reg_op] */ \
2907 arm_access_memory(load, + reg_offset, reg, u8, no, no_op); \
2908 break; \
2909 \
2910 case 0x7E: \
2911 /* STRB rd, [rn + reg_op]! */ \
2912 arm_access_memory(store, + reg_offset, reg, u8, yes, no_op); \
2913 break; \
2914 \
2915 case 0x7F: \
2916 /* LDRBT rd, [rn + reg_op]! */ \
2917 arm_access_memory(load, + reg_offset, reg, u8, yes, no_op); \
2918 break; \
2919 \
2920 case 0x80: \
2921 /* STMDA rn, rlist */ \
2922 arm_block_memory(store, down_a, no, no); \
2923 break; \
2924 \
2925 case 0x81: \
2926 /* LDMDA rn, rlist */ \
2927 arm_block_memory(load, down_a, no, no); \
2928 break; \
2929 \
2930 case 0x82: \
2931 /* STMDA rn!, rlist */ \
2932 arm_block_memory(store, down_a, down, no); \
2933 break; \
2934 \
2935 case 0x83: \
2936 /* LDMDA rn!, rlist */ \
2937 arm_block_memory(load, down_a, down, no); \
2938 break; \
2939 \
2940 case 0x84: \
2941 /* STMDA rn, rlist^ */ \
2942 arm_block_memory(store, down_a, no, yes); \
2943 break; \
2944 \
2945 case 0x85: \
2946 /* LDMDA rn, rlist^ */ \
2947 arm_block_memory(load, down_a, no, yes); \
2948 break; \
2949 \
2950 case 0x86: \
2951 /* STMDA rn!, rlist^ */ \
2952 arm_block_memory(store, down_a, down, yes); \
2953 break; \
2954 \
2955 case 0x87: \
2956 /* LDMDA rn!, rlist^ */ \
2957 arm_block_memory(load, down_a, down, yes); \
2958 break; \
2959 \
2960 case 0x88: \
2961 /* STMIA rn, rlist */ \
2962 arm_block_memory(store, no, no, no); \
2963 break; \
2964 \
2965 case 0x89: \
2966 /* LDMIA rn, rlist */ \
2967 arm_block_memory(load, no, no, no); \
2968 break; \
2969 \
2970 case 0x8A: \
2971 /* STMIA rn!, rlist */ \
2972 arm_block_memory(store, no, up, no); \
2973 break; \
2974 \
2975 case 0x8B: \
2976 /* LDMIA rn!, rlist */ \
2977 arm_block_memory(load, no, up, no); \
2978 break; \
2979 \
2980 case 0x8C: \
2981 /* STMIA rn, rlist^ */ \
2982 arm_block_memory(store, no, no, yes); \
2983 break; \
2984 \
2985 case 0x8D: \
2986 /* LDMIA rn, rlist^ */ \
2987 arm_block_memory(load, no, no, yes); \
2988 break; \
2989 \
2990 case 0x8E: \
2991 /* STMIA rn!, rlist^ */ \
2992 arm_block_memory(store, no, up, yes); \
2993 break; \
2994 \
2995 case 0x8F: \
2996 /* LDMIA rn!, rlist^ */ \
2997 arm_block_memory(load, no, up, yes); \
2998 break; \
2999 \
3000 case 0x90: \
3001 /* STMDB rn, rlist */ \
3002 arm_block_memory(store, down_b, no, no); \
3003 break; \
3004 \
3005 case 0x91: \
3006 /* LDMDB rn, rlist */ \
3007 arm_block_memory(load, down_b, no, no); \
3008 break; \
3009 \
3010 case 0x92: \
3011 /* STMDB rn!, rlist */ \
3012 arm_block_memory(store, down_b, down, no); \
3013 break; \
3014 \
3015 case 0x93: \
3016 /* LDMDB rn!, rlist */ \
3017 arm_block_memory(load, down_b, down, no); \
3018 break; \
3019 \
3020 case 0x94: \
3021 /* STMDB rn, rlist^ */ \
3022 arm_block_memory(store, down_b, no, yes); \
3023 break; \
3024 \
3025 case 0x95: \
3026 /* LDMDB rn, rlist^ */ \
3027 arm_block_memory(load, down_b, no, yes); \
3028 break; \
3029 \
3030 case 0x96: \
3031 /* STMDB rn!, rlist^ */ \
3032 arm_block_memory(store, down_b, down, yes); \
3033 break; \
3034 \
3035 case 0x97: \
3036 /* LDMDB rn!, rlist^ */ \
3037 arm_block_memory(load, down_b, down, yes); \
3038 break; \
3039 \
3040 case 0x98: \
3041 /* STMIB rn, rlist */ \
3042 arm_block_memory(store, up, no, no); \
3043 break; \
3044 \
3045 case 0x99: \
3046 /* LDMIB rn, rlist */ \
3047 arm_block_memory(load, up, no, no); \
3048 break; \
3049 \
3050 case 0x9A: \
3051 /* STMIB rn!, rlist */ \
3052 arm_block_memory(store, up, up, no); \
3053 break; \
3054 \
3055 case 0x9B: \
3056 /* LDMIB rn!, rlist */ \
3057 arm_block_memory(load, up, up, no); \
3058 break; \
3059 \
3060 case 0x9C: \
3061 /* STMIB rn, rlist^ */ \
3062 arm_block_memory(store, up, no, yes); \
3063 break; \
3064 \
3065 case 0x9D: \
3066 /* LDMIB rn, rlist^ */ \
3067 arm_block_memory(load, up, no, yes); \
3068 break; \
3069 \
3070 case 0x9E: \
3071 /* STMIB rn!, rlist^ */ \
3072 arm_block_memory(store, up, up, yes); \
3073 break; \
3074 \
3075 case 0x9F: \
3076 /* LDMIB rn!, rlist^ */ \
3077 arm_block_memory(load, up, up, yes); \
3078 break; \
3079 \
3080 case 0xA0: \
3081 case 0xA1: \
3082 case 0xA2: \
3083 case 0xA3: \
3084 case 0xA4: \
3085 case 0xA5: \
3086 case 0xA6: \
3087 case 0xA7: \
3088 case 0xA8: \
3089 case 0xA9: \
3090 case 0xAA: \
3091 case 0xAB: \
3092 case 0xAC: \
3093 case 0xAD: \
3094 case 0xAE: \
3095 case 0xAF: \
3096 { \
3097 /* B offset */ \
3098 arm_decode_branch(); \
3099 arm_pc_offset_update(offset + 8); \
3100 break; \
3101 } \
3102 \
3103 case 0xB0 ... 0xBF: \
3104 { \
3105 /* BL offset */ \
3106 arm_decode_branch(); \
3107 reg[REG_LR] = pc + 4; \
3108 arm_pc_offset_update(offset + 8); \
3109 break; \
3110 } \
3111 \
3112 case 0xC0 ... 0xEF: \
3113 /* coprocessor instructions, reserved on GBA */ \
3114 break; \
3115 \
3116 case 0xF0 ... 0xFF: \
3117 { \
3118 /* SWI comment */ \
3119 u32 swi_comment = opcode & 0x00FFFFFF; \
3120 \
3121 switch(swi_comment >> 16) \
3122 { \
3123 /* Jump to BIOS SWI handler */ \
3124 default: \
3125 reg_mode[MODE_SUPERVISOR][6] = pc + 4; \
3126 collapse_flags(); \
3127 spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; \
3128 reg[REG_PC] = 0x00000008; \
3129 arm_update_pc(); \
3130 reg[REG_CPSR] = (reg[REG_CPSR] & ~0x1F) | 0x13; \
3131 set_cpu_mode(MODE_SUPERVISOR); \
3132 break; \
3133 } \
3134 break; \
3135 } \
3136 } \
3137 \
3138 skip_instruction: \
3139
3140#define execute_thumb_instruction() \
3141 using_instruction(thumb); \
3142 check_pc_region(); \
3143 pc &= ~0x01; \
3144 opcode = address16(pc_address_block, (pc & 0x7FFF)); \
3145 \
3146 switch((opcode >> 8) & 0xFF) \
3147 { \
3148 case 0x00 ... 0x07: \
3149 /* LSL rd, rs, offset */ \
3150 thumb_shift(shift, lsl, imm); \
3151 break; \
3152 \
3153 case 0x08 ... 0x0F: \
3154 /* LSR rd, rs, offset */ \
3155 thumb_shift(shift, lsr, imm); \
3156 break; \
3157 \
3158 case 0x10 ... 0x17: \
3159 /* ASR rd, rs, offset */ \
3160 thumb_shift(shift, asr, imm); \
3161 break; \
3162 \
3163 case 0x18 ... 0x19: \
3164 /* ADD rd, rs, rn */ \
3165 thumb_add(add_sub, rd, reg[rs], reg[rn]); \
3166 break; \
3167 \
3168 case 0x1A ... 0x1B: \
3169 /* SUB rd, rs, rn */ \
3170 thumb_sub(add_sub, rd, reg[rs], reg[rn]); \
3171 break; \
3172 \
3173 case 0x1C ... 0x1D: \
3174 /* ADD rd, rs, imm */ \
3175 thumb_add(add_sub_imm, rd, reg[rs], imm); \
3176 break; \
3177 \
3178 case 0x1E ... 0x1F: \
3179 /* SUB rd, rs, imm */ \
3180 thumb_sub(add_sub_imm, rd, reg[rs], imm); \
3181 break; \
3182 \
3183 case 0x20: \
3184 /* MOV r0, imm */ \
3185 thumb_logic(imm, 0, imm); \
3186 break; \
3187 \
3188 case 0x21: \
3189 /* MOV r1, imm */ \
3190 thumb_logic(imm, 1, imm); \
3191 break; \
3192 \
3193 case 0x22: \
3194 /* MOV r2, imm */ \
3195 thumb_logic(imm, 2, imm); \
3196 break; \
3197 \
3198 case 0x23: \
3199 /* MOV r3, imm */ \
3200 thumb_logic(imm, 3, imm); \
3201 break; \
3202 \
3203 case 0x24: \
3204 /* MOV r4, imm */ \
3205 thumb_logic(imm, 4, imm); \
3206 break; \
3207 \
3208 case 0x25: \
3209 /* MOV r5, imm */ \
3210 thumb_logic(imm, 5, imm); \
3211 break; \
3212 \
3213 case 0x26: \
3214 /* MOV r6, imm */ \
3215 thumb_logic(imm, 6, imm); \
3216 break; \
3217 \
3218 case 0x27: \
3219 /* MOV r7, imm */ \
3220 thumb_logic(imm, 7, imm); \
3221 break; \
3222 \
3223 case 0x28: \
3224 /* CMP r0, imm */ \
3225 thumb_test_sub(imm, reg[0], imm); \
3226 break; \
3227 \
3228 case 0x29: \
3229 /* CMP r1, imm */ \
3230 thumb_test_sub(imm, reg[1], imm); \
3231 break; \
3232 \
3233 case 0x2A: \
3234 /* CMP r2, imm */ \
3235 thumb_test_sub(imm, reg[2], imm); \
3236 break; \
3237 \
3238 case 0x2B: \
3239 /* CMP r3, imm */ \
3240 thumb_test_sub(imm, reg[3], imm); \
3241 break; \
3242 \
3243 case 0x2C: \
3244 /* CMP r4, imm */ \
3245 thumb_test_sub(imm, reg[4], imm); \
3246 break; \
3247 \
3248 case 0x2D: \
3249 /* CMP r5, imm */ \
3250 thumb_test_sub(imm, reg[5], imm); \
3251 break; \
3252 \
3253 case 0x2E: \
3254 /* CMP r6, imm */ \
3255 thumb_test_sub(imm, reg[6], imm); \
3256 break; \
3257 \
3258 case 0x2F: \
3259 /* CMP r7, imm */ \
3260 thumb_test_sub(imm, reg[7], imm); \
3261 break; \
3262 \
3263 case 0x30: \
3264 /* ADD r0, imm */ \
3265 thumb_add(imm, 0, reg[0], imm); \
3266 break; \
3267 \
3268 case 0x31: \
3269 /* ADD r1, imm */ \
3270 thumb_add(imm, 1, reg[1], imm); \
3271 break; \
3272 \
3273 case 0x32: \
3274 /* ADD r2, imm */ \
3275 thumb_add(imm, 2, reg[2], imm); \
3276 break; \
3277 \
3278 case 0x33: \
3279 /* ADD r3, imm */ \
3280 thumb_add(imm, 3, reg[3], imm); \
3281 break; \
3282 \
3283 case 0x34: \
3284 /* ADD r4, imm */ \
3285 thumb_add(imm, 4, reg[4], imm); \
3286 break; \
3287 \
3288 case 0x35: \
3289 /* ADD r5, imm */ \
3290 thumb_add(imm, 5, reg[5], imm); \
3291 break; \
3292 \
3293 case 0x36: \
3294 /* ADD r6, imm */ \
3295 thumb_add(imm, 6, reg[6], imm); \
3296 break; \
3297 \
3298 case 0x37: \
3299 /* ADD r7, imm */ \
3300 thumb_add(imm, 7, reg[7], imm); \
3301 break; \
3302 \
3303 case 0x38: \
3304 /* SUB r0, imm */ \
3305 thumb_sub(imm, 0, reg[0], imm); \
3306 break; \
3307 \
3308 case 0x39: \
3309 /* SUB r1, imm */ \
3310 thumb_sub(imm, 1, reg[1], imm); \
3311 break; \
3312 \
3313 case 0x3A: \
3314 /* SUB r2, imm */ \
3315 thumb_sub(imm, 2, reg[2], imm); \
3316 break; \
3317 \
3318 case 0x3B: \
3319 /* SUB r3, imm */ \
3320 thumb_sub(imm, 3, reg[3], imm); \
3321 break; \
3322 \
3323 case 0x3C: \
3324 /* SUB r4, imm */ \
3325 thumb_sub(imm, 4, reg[4], imm); \
3326 break; \
3327 \
3328 case 0x3D: \
3329 /* SUB r5, imm */ \
3330 thumb_sub(imm, 5, reg[5], imm); \
3331 break; \
3332 \
3333 case 0x3E: \
3334 /* SUB r6, imm */ \
3335 thumb_sub(imm, 6, reg[6], imm); \
3336 break; \
3337 \
3338 case 0x3F: \
3339 /* SUB r7, imm */ \
3340 thumb_sub(imm, 7, reg[7], imm); \
3341 break; \
3342 \
3343 case 0x40: \
3344 switch((opcode >> 6) & 0x03) \
3345 { \
3346 case 0x00: \
3347 /* AND rd, rs */ \
3348 thumb_logic(alu_op, rd, reg[rd] & reg[rs]); \
3349 break; \
3350 \
3351 case 0x01: \
3352 /* EOR rd, rs */ \
3353 thumb_logic(alu_op, rd, reg[rd] ^ reg[rs]); \
3354 break; \
3355 \
3356 case 0x02: \
3357 /* LSL rd, rs */ \
3358 thumb_shift(alu_op, lsl, reg); \
3359 break; \
3360 \
3361 case 0x03: \
3362 /* LSR rd, rs */ \
3363 thumb_shift(alu_op, lsr, reg); \
3364 break; \
3365 } \
3366 break; \
3367 \
3368 case 0x41: \
3369 switch((opcode >> 6) & 0x03) \
3370 { \
3371 case 0x00: \
3372 /* ASR rd, rs */ \
3373 thumb_shift(alu_op, asr, reg); \
3374 break; \
3375 \
3376 case 0x01: \
3377 /* ADC rd, rs */ \
3378 thumb_add(alu_op, rd, reg[rd] + reg[rs], c_flag); \
3379 break; \
3380 \
3381 case 0x02: \
3382 /* SBC rd, rs */ \
3383 thumb_sub(alu_op, rd, reg[rd] - reg[rs], (c_flag ^ 1)); \
3384 break; \
3385 \
3386 case 0x03: \
3387 /* ROR rd, rs */ \
3388 thumb_shift(alu_op, ror, reg); \
3389 break; \
3390 } \
3391 break; \
3392 \
3393 case 0x42: \
3394 switch((opcode >> 6) & 0x03) \
3395 { \
3396 case 0x00: \
3397 /* TST rd, rs */ \
3398 thumb_test_logic(alu_op, reg[rd] & reg[rs]); \
3399 break; \
3400 \
3401 case 0x01: \
3402 /* NEG rd, rs */ \
3403 thumb_sub(alu_op, rd, 0, reg[rs]); \
3404 break; \
3405 \
3406 case 0x02: \
3407 /* CMP rd, rs */ \
3408 thumb_test_sub(alu_op, reg[rd], reg[rs]); \
3409 break; \
3410 \
3411 case 0x03: \
3412 /* CMN rd, rs */ \
3413 thumb_test_add(alu_op, reg[rd], reg[rs]); \
3414 break; \
3415 } \
3416 break; \
3417 \
3418 case 0x43: \
3419 switch((opcode >> 6) & 0x03) \
3420 { \
3421 case 0x00: \
3422 /* ORR rd, rs */ \
3423 thumb_logic(alu_op, rd, reg[rd] | reg[rs]); \
3424 break; \
3425 \
3426 case 0x01: \
3427 /* MUL rd, rs */ \
3428 thumb_logic(alu_op, rd, reg[rd] * reg[rs]); \
3429 break; \
3430 \
3431 case 0x02: \
3432 /* BIC rd, rs */ \
3433 thumb_logic(alu_op, rd, reg[rd] & (~reg[rs])); \
3434 break; \
3435 \
3436 case 0x03: \
3437 /* MVN rd, rs */ \
3438 thumb_logic(alu_op, rd, ~reg[rs]); \
3439 break; \
3440 } \
3441 break; \
3442 \
3443 case 0x44: \
3444 /* ADD rd, rs */ \
3445 thumb_hireg_op(reg[rd] + reg[rs]); \
3446 break; \
3447 \
3448 case 0x45: \
3449 /* CMP rd, rs */ \
3450 { \
3451 thumb_pc_offset(4); \
3452 thumb_decode_hireg_op(); \
3453 u32 _sa = reg[rd]; \
3454 u32 _sb = reg[rs]; \
3455 u32 dest = _sa - _sb; \
3456 thumb_pc_offset(-2); \
3457 calculate_flags_sub(dest, _sa, _sb); \
3458 } \
3459 break; \
3460 \
3461 case 0x46: \
3462 /* MOV rd, rs */ \
3463 thumb_hireg_op(reg[rs]); \
3464 break; \
3465 \
3466 case 0x47: \
3467 /* BX rs */ \
3468 { \
3469 thumb_decode_hireg_op(); \
3470 u32 src; \
3471 thumb_pc_offset(4); \
3472 src = reg[rs]; \
3473 if(src & 0x01) \
3474 { \
3475 src -= 1; \
3476 thumb_pc_offset_update_direct(src); \
3477 } \
3478 else \
3479 { \
3480 /* Switch to ARM mode */ \
3481 thumb_pc_offset_update_direct(src); \
3482 reg[REG_CPSR] &= ~0x20; \
3483 collapse_flags(); \
3484 goto arm_loop; \
3485 } \
3486 } \
3487 break; \
3488 \
3489 case 0x48: \
3490 /* LDR r0, [pc + imm] */ \
3491 thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[0], u32); \
3492 break; \
3493 \
3494 case 0x49: \
3495 /* LDR r1, [pc + imm] */ \
3496 thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[1], u32); \
3497 break; \
3498 \
3499 case 0x4A: \
3500 /* LDR r2, [pc + imm] */ \
3501 thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[2], u32); \
3502 break; \
3503 \
3504 case 0x4B: \
3505 /* LDR r3, [pc + imm] */ \
3506 thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[3], u32); \
3507 break; \
3508 \
3509 case 0x4C: \
3510 /* LDR r4, [pc + imm] */ \
3511 thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[4], u32); \
3512 break; \
3513 \
3514 case 0x4D: \
3515 /* LDR r5, [pc + imm] */ \
3516 thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[5], u32); \
3517 break; \
3518 \
3519 case 0x4E: \
3520 /* LDR r6, [pc + imm] */ \
3521 thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[6], u32); \
3522 break; \
3523 \
3524 case 0x4F: \
3525 /* LDR r7, [pc + imm] */ \
3526 thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[7], u32); \
3527 break; \
3528 \
3529 case 0x50 ... 0x51: \
3530 /* STR rd, [rb + ro] */ \
3531 thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u32); \
3532 break; \
3533 \
3534 case 0x52 ... 0x53: \
3535 /* STRH rd, [rb + ro] */ \
3536 thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u16); \
3537 break; \
3538 \
3539 case 0x54 ... 0x55: \
3540 /* STRB rd, [rb + ro] */ \
3541 thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u8); \
3542 break; \
3543 \
3544 case 0x56 ... 0x57: \
3545 /* LDSB rd, [rb + ro] */ \
3546 thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], s8); \
3547 break; \
3548 \
3549 case 0x58 ... 0x59: \
3550 /* LDR rd, [rb + ro] */ \
3551 thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u32); \
3552 break; \
3553 \
3554 case 0x5A ... 0x5B: \
3555 /* LDRH rd, [rb + ro] */ \
3556 thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u16); \
3557 break; \
3558 \
3559 case 0x5C ... 0x5D: \
3560 /* LDRB rd, [rb + ro] */ \
3561 thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u8); \
3562 break; \
3563 \
3564 case 0x5E ... 0x5F: \
3565 /* LDSH rd, [rb + ro] */ \
3566 thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], s16); \
3567 break; \
3568 \
3569 case 0x60 ... 0x67: \
3570 /* STR rd, [rb + imm] */ \
3571 thumb_access_memory(store, mem_imm, reg[rb] + (imm * 4), reg[rd], u32); \
3572 break; \
3573 \
3574 case 0x68 ... 0x6F: \
3575 /* LDR rd, [rb + imm] */ \
3576 thumb_access_memory(load, mem_imm, reg[rb] + (imm * 4), reg[rd], u32); \
3577 break; \
3578 \
3579 case 0x70 ... 0x77: \
3580 /* STRB rd, [rb + imm] */ \
3581 thumb_access_memory(store, mem_imm, reg[rb] + imm, reg[rd], u8); \
3582 break; \
3583 \
3584 case 0x78 ... 0x7F: \
3585 /* LDRB rd, [rb + imm] */ \
3586 thumb_access_memory(load, mem_imm, reg[rb] + imm, reg[rd], u8); \
3587 break; \
3588 \
3589 case 0x80 ... 0x87: \
3590 /* STRH rd, [rb + imm] */ \
3591 thumb_access_memory(store, mem_imm, reg[rb] + (imm * 2), reg[rd], u16); \
3592 break; \
3593 \
3594 case 0x88 ... 0x8F: \
3595 /* LDRH rd, [rb + imm] */ \
3596 thumb_access_memory(load, mem_imm, reg[rb] + (imm * 2), reg[rd], u16); \
3597 break; \
3598 \
3599 case 0x90: \
3600 /* STR r0, [sp + imm] */ \
3601 thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[0], u32); \
3602 break; \
3603 \
3604 case 0x91: \
3605 /* STR r1, [sp + imm] */ \
3606 thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[1], u32); \
3607 break; \
3608 \
3609 case 0x92: \
3610 /* STR r2, [sp + imm] */ \
3611 thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[2], u32); \
3612 break; \
3613 \
3614 case 0x93: \
3615 /* STR r3, [sp + imm] */ \
3616 thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[3], u32); \
3617 break; \
3618 \
3619 case 0x94: \
3620 /* STR r4, [sp + imm] */ \
3621 thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[4], u32); \
3622 break; \
3623 \
3624 case 0x95: \
3625 /* STR r5, [sp + imm] */ \
3626 thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[5], u32); \
3627 break; \
3628 \
3629 case 0x96: \
3630 /* STR r6, [sp + imm] */ \
3631 thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[6], u32); \
3632 break; \
3633 \
3634 case 0x97: \
3635 /* STR r7, [sp + imm] */ \
3636 thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[7], u32); \
3637 break; \
3638 \
3639 case 0x98: \
3640 /* LDR r0, [sp + imm] */ \
3641 thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[0], u32); \
3642 break; \
3643 \
3644 case 0x99: \
3645 /* LDR r1, [sp + imm] */ \
3646 thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[1], u32); \
3647 break; \
3648 \
3649 case 0x9A: \
3650 /* LDR r2, [sp + imm] */ \
3651 thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[2], u32); \
3652 break; \
3653 \
3654 case 0x9B: \
3655 /* LDR r3, [sp + imm] */ \
3656 thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[3], u32); \
3657 break; \
3658 \
3659 case 0x9C: \
3660 /* LDR r4, [sp + imm] */ \
3661 thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[4], u32); \
3662 break; \
3663 \
3664 case 0x9D: \
3665 /* LDR r5, [sp + imm] */ \
3666 thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[5], u32); \
3667 break; \
3668 \
3669 case 0x9E: \
3670 /* LDR r6, [sp + imm] */ \
3671 thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[6], u32); \
3672 break; \
3673 \
3674 case 0x9F: \
3675 /* LDR r7, [sp + imm] */ \
3676 thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[7], u32); \
3677 break; \
3678 \
3679 case 0xA0: \
3680 /* ADD r0, pc, +imm */ \
3681 thumb_add_noflags(imm, 0, (pc & ~2) + 4, (imm * 4)); \
3682 break; \
3683 \
3684 case 0xA1: \
3685 /* ADD r1, pc, +imm */ \
3686 thumb_add_noflags(imm, 1, (pc & ~2) + 4, (imm * 4)); \
3687 break; \
3688 \
3689 case 0xA2: \
3690 /* ADD r2, pc, +imm */ \
3691 thumb_add_noflags(imm, 2, (pc & ~2) + 4, (imm * 4)); \
3692 break; \
3693 \
3694 case 0xA3: \
3695 /* ADD r3, pc, +imm */ \
3696 thumb_add_noflags(imm, 3, (pc & ~2) + 4, (imm * 4)); \
3697 break; \
3698 \
3699 case 0xA4: \
3700 /* ADD r4, pc, +imm */ \
3701 thumb_add_noflags(imm, 4, (pc & ~2) + 4, (imm * 4)); \
3702 break; \
3703 \
3704 case 0xA5: \
3705 /* ADD r5, pc, +imm */ \
3706 thumb_add_noflags(imm, 5, (pc & ~2) + 4, (imm * 4)); \
3707 break; \
3708 \
3709 case 0xA6: \
3710 /* ADD r6, pc, +imm */ \
3711 thumb_add_noflags(imm, 6, (pc & ~2) + 4, (imm * 4)); \
3712 break; \
3713 \
3714 case 0xA7: \
3715 /* ADD r7, pc, +imm */ \
3716 thumb_add_noflags(imm, 7, (pc & ~2) + 4, (imm * 4)); \
3717 break; \
3718 \
3719 case 0xA8: \
3720 /* ADD r0, sp, +imm */ \
3721 thumb_add_noflags(imm, 0, reg[REG_SP], (imm * 4)); \
3722 break; \
3723 \
3724 case 0xA9: \
3725 /* ADD r1, sp, +imm */ \
3726 thumb_add_noflags(imm, 1, reg[REG_SP], (imm * 4)); \
3727 break; \
3728 \
3729 case 0xAA: \
3730 /* ADD r2, sp, +imm */ \
3731 thumb_add_noflags(imm, 2, reg[REG_SP], (imm * 4)); \
3732 break; \
3733 \
3734 case 0xAB: \
3735 /* ADD r3, sp, +imm */ \
3736 thumb_add_noflags(imm, 3, reg[REG_SP], (imm * 4)); \
3737 break; \
3738 \
3739 case 0xAC: \
3740 /* ADD r4, sp, +imm */ \
3741 thumb_add_noflags(imm, 4, reg[REG_SP], (imm * 4)); \
3742 break; \
3743 \
3744 case 0xAD: \
3745 /* ADD r5, sp, +imm */ \
3746 thumb_add_noflags(imm, 5, reg[REG_SP], (imm * 4)); \
3747 break; \
3748 \
3749 case 0xAE: \
3750 /* ADD r6, sp, +imm */ \
3751 thumb_add_noflags(imm, 6, reg[REG_SP], (imm * 4)); \
3752 break; \
3753 \
3754 case 0xAF: \
3755 /* ADD r7, sp, +imm */ \
3756 thumb_add_noflags(imm, 7, reg[REG_SP], (imm * 4)); \
3757 break; \
3758 \
3759 case 0xB0 ... 0xB3: \
3760 if((opcode >> 7) & 0x01) \
3761 { \
3762 /* ADD sp, -imm */ \
3763 thumb_add_noflags(add_sp, 13, reg[REG_SP], -(imm * 4)); \
3764 } \
3765 else \
3766 { \
3767 /* ADD sp, +imm */ \
3768 thumb_add_noflags(add_sp, 13, reg[REG_SP], (imm * 4)); \
3769 } \
3770 break; \
3771 \
3772 case 0xB4: \
3773 /* PUSH rlist */ \
3774 thumb_block_memory(store, down, no_op, 13); \
3775 break; \
3776 \
3777 case 0xB5: \
3778 /* PUSH rlist, lr */ \
3779 thumb_block_memory(store, push_lr, push_lr, 13); \
3780 break; \
3781 \
3782 case 0xBC: \
3783 /* POP rlist */ \
3784 thumb_block_memory(load, no_op, up, 13); \
3785 break; \
3786 \
3787 case 0xBD: \
3788 /* POP rlist, pc */ \
3789 thumb_block_memory(load, no_op, pop_pc, 13); \
3790 break; \
3791 \
3792 case 0xC0: \
3793 /* STMIA r0!, rlist */ \
3794 thumb_block_memory(store, no_op, up, 0); \
3795 break; \
3796 \
3797 case 0xC1: \
3798 /* STMIA r1!, rlist */ \
3799 thumb_block_memory(store, no_op, up, 1); \
3800 break; \
3801 \
3802 case 0xC2: \
3803 /* STMIA r2!, rlist */ \
3804 thumb_block_memory(store, no_op, up, 2); \
3805 break; \
3806 \
3807 case 0xC3: \
3808 /* STMIA r3!, rlist */ \
3809 thumb_block_memory(store, no_op, up, 3); \
3810 break; \
3811 \
3812 case 0xC4: \
3813 /* STMIA r4!, rlist */ \
3814 thumb_block_memory(store, no_op, up, 4); \
3815 break; \
3816 \
3817 case 0xC5: \
3818 /* STMIA r5!, rlist */ \
3819 thumb_block_memory(store, no_op, up, 5); \
3820 break; \
3821 \
3822 case 0xC6: \
3823 /* STMIA r6!, rlist */ \
3824 thumb_block_memory(store, no_op, up, 6); \
3825 break; \
3826 \
3827 case 0xC7: \
3828 /* STMIA r7!, rlist */ \
3829 thumb_block_memory(store, no_op, up, 7); \
3830 break; \
3831 \
3832 case 0xC8: \
3833 /* LDMIA r0!, rlist */ \
3834 thumb_block_memory(load, no_op, up, 0); \
3835 break; \
3836 \
3837 case 0xC9: \
3838 /* LDMIA r1!, rlist */ \
3839 thumb_block_memory(load, no_op, up, 1); \
3840 break; \
3841 \
3842 case 0xCA: \
3843 /* LDMIA r2!, rlist */ \
3844 thumb_block_memory(load, no_op, up, 2); \
3845 break; \
3846 \
3847 case 0xCB: \
3848 /* LDMIA r3!, rlist */ \
3849 thumb_block_memory(load, no_op, up, 3); \
3850 break; \
3851 \
3852 case 0xCC: \
3853 /* LDMIA r4!, rlist */ \
3854 thumb_block_memory(load, no_op, up, 4); \
3855 break; \
3856 \
3857 case 0xCD: \
3858 /* LDMIA r5!, rlist */ \
3859 thumb_block_memory(load, no_op, up, 5); \
3860 break; \
3861 \
3862 case 0xCE: \
3863 /* LDMIA r6!, rlist */ \
3864 thumb_block_memory(load, no_op, up, 6); \
3865 break; \
3866 \
3867 case 0xCF: \
3868 /* LDMIA r7!, rlist */ \
3869 thumb_block_memory(load, no_op, up, 7); \
3870 break; \
3871 \
3872 case 0xD0: \
3873 /* BEQ label */ \
3874 thumb_conditional_branch(z_flag == 1); \
3875 break; \
3876 \
3877 case 0xD1: \
3878 /* BNE label */ \
3879 thumb_conditional_branch(z_flag == 0); \
3880 break; \
3881 \
3882 case 0xD2: \
3883 /* BCS label */ \
3884 thumb_conditional_branch(c_flag == 1); \
3885 break; \
3886 \
3887 case 0xD3: \
3888 /* BCC label */ \
3889 thumb_conditional_branch(c_flag == 0); \
3890 break; \
3891 \
3892 case 0xD4: \
3893 /* BMI label */ \
3894 thumb_conditional_branch(n_flag == 1); \
3895 break; \
3896 \
3897 case 0xD5: \
3898 /* BPL label */ \
3899 thumb_conditional_branch(n_flag == 0); \
3900 break; \
3901 \
3902 case 0xD6: \
3903 /* BVS label */ \
3904 thumb_conditional_branch(v_flag == 1); \
3905 break; \
3906 \
3907 case 0xD7: \
3908 /* BVC label */ \
3909 thumb_conditional_branch(v_flag == 0); \
3910 break; \
3911 \
3912 case 0xD8: \
3913 /* BHI label */ \
3914 thumb_conditional_branch(c_flag & (z_flag ^ 1)); \
3915 break; \
3916 \
3917 case 0xD9: \
3918 /* BLS label */ \
3919 thumb_conditional_branch((c_flag == 0) | z_flag); \
3920 break; \
3921 \
3922 case 0xDA: \
3923 /* BGE label */ \
3924 thumb_conditional_branch(n_flag == v_flag); \
3925 break; \
3926 \
3927 case 0xDB: \
3928 /* BLT label */ \
3929 thumb_conditional_branch(n_flag != v_flag); \
3930 break; \
3931 \
3932 case 0xDC: \
3933 /* BGT label */ \
3934 thumb_conditional_branch((z_flag == 0) & (n_flag == v_flag)); \
3935 break; \
3936 \
3937 case 0xDD: \
3938 /* BLE label */ \
3939 thumb_conditional_branch(z_flag | (n_flag != v_flag)); \
3940 break; \
3941 \
3942 case 0xDF: \
3943 { \
3944 /* SWI comment */ \
3945 u32 swi_comment = opcode & 0xFF; \
3946 \
3947 switch(swi_comment) \
3948 { \
3949 default: \
3950 reg_mode[MODE_SUPERVISOR][6] = pc + 2; \
3951 spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; \
3952 reg[REG_PC] = 0x00000008; \
3953 thumb_update_pc(); \
3954 reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13; \
3955 set_cpu_mode(MODE_SUPERVISOR); \
3956 collapse_flags(); \
3957 goto arm_loop; \
3958 } \
3959 break; \
3960 } \
3961 \
3962 case 0xE0 ... 0xE7: \
3963 { \
3964 /* B label */ \
3965 thumb_decode_branch(); \
3966 thumb_pc_offset_update(((s32)(offset << 21) >> 20) + 4); \
3967 break; \
3968 } \
3969 \
3970 case 0xF0 ... 0xF7: \
3971 { \
3972 /* (low word) BL label */ \
3973 thumb_decode_branch(); \
3974 reg[REG_LR] = pc + 4 + ((s32)(offset << 21) >> 9); \
3975 thumb_pc_offset(2); \
3976 break; \
3977 } \
3978 \
3979 case 0xF8 ... 0xFF: \
3980 { \
3981 /* (high word) BL label */ \
3982 thumb_decode_branch(); \
3983 u32 lr = (pc + 2) | 0x01; \
3984 pc = reg[REG_LR] + (offset * 2); \
3985 reg[REG_LR] = lr; \
3986 reg[REG_PC] = pc; \
3987 break; \
3988 } \
3989 } \
3990
3991void print_arm_registers()
3992{
3993 u32 i, i2, i3;
3994
3995 for(i = 0, i3 = 0; i < 4; i++)
3996 {
3997 debug_screen_printf(" ");
3998 for(i2 = 0; i2 < 4; i2++, i3++)
3999 {
4000 debug_screen_printf("R%02d %08x ", i3, reg[i3]);
4001 }
4002 debug_screen_newline(1);
4003 }
4004}
4005
4006void print_thumb_instruction()
4007{
4008 debug_screen_printf("Thumb instruction at PC: %04x",
4009 read_memory16(reg[REG_PC]));
4010 debug_screen_newline(1);
4011}
4012
4013void print_arm_instruction()
4014{
4015 debug_screen_printf("ARM instruction at PC: %08x",
4016 read_memory32(reg[REG_PC]));
4017 debug_screen_newline(1);
4018}
4019
4020void print_flags()
4021{
4022 u32 cpsr = reg[REG_CPSR];
4023 debug_screen_newline(1);
4024 debug_screen_printf(
4025 " N: %d Z: %d C: %d V: %d CPSR: %08x SPSR: %08x mode: %s",
4026 (cpsr >> 31) & 0x01, (cpsr >> 30) & 0x01, (cpsr >> 29) & 0x01,
4027 (cpsr >> 28) & 0x01, cpsr, spsr[reg[CPU_MODE]],
4028 cpu_mode_names[reg[CPU_MODE]]);
4029 debug_screen_newline(2);
4030}
4031
4032const u32 stack_print_lines = 2;
4033
4034void print_stack()
4035{
4036 u32 i, i2, i3;
4037
4038 debug_screen_printf("Stack:");
4039 debug_screen_newline(1);
4040
4041 for(i = 0, i3 = reg[REG_SP]; i < stack_print_lines; i++)
4042 {
4043 for(i2 = 0; i2 < 5; i2++, i3 += 4)
4044 {
4045 debug_screen_printf(" %08x", read_memory32(i3));
4046 }
4047 if(i != stack_print_lines)
4048 debug_screen_newline(1);
4049 }
4050
4051 debug_screen_newline(1);
4052}
4053
4054u32 instruction_count = 0;
4055
4056u32 output_field = 0;
4057const u32 num_output_fields = 2;
4058
4059u32 last_instruction = 0;
4060
4061u32 in_interrupt = 0;
4062
bbba3209 4063void debug_on()
2823a4c8 4064{
4065 current_debug_state = STEP;
4066 debug_screen_start();
4067}
4068
bbba3209 4069void debug_off(debug_state new_debug_state)
2823a4c8 4070{
4071 current_debug_state = new_debug_state;
4072 debug_screen_end();
4073}
4074
bbba3209 4075void function_cc step_debug(u32 pc, u32 cycles)
2823a4c8 4076{
4077 u32 thumb = 0;
4078
4079 reg[REG_PC] = pc;
4080
4081 if(reg[REG_CPSR] & 0x20)
4082 thumb = 1;
4083
4084 instruction_count++;
4085
4086 switch(current_debug_state)
4087 {
4088 case PC_BREAKPOINT:
4089 if(reg[REG_PC] == breakpoint_value)
4090 debug_on();
4091
4092 break;
4093
4094 case Z_BREAKPOINT:
4095 if(reg[REG_Z_FLAG] == 1)
4096 debug_on();
4097
4098 break;
4099
4100 case VCOUNT_BREAKPOINT:
4101 if(io_registers[REG_VCOUNT] == breakpoint_value)
4102 debug_on();
4103
4104 break;
4105
4106 case COUNTDOWN_BREAKPOINT:
4107 if(breakpoint_value == 0)
4108 debug_on();
4109 else
4110 breakpoint_value--;
4111
4112 break;
4113
4114 case COUNTDOWN_BREAKPOINT_B:
4115 if(breakpoint_value == instruction_count)
4116 debug_on();
4117
4118 break;
4119
4120 case COUNTDOWN_BREAKPOINT_C:
4121 {
4122 if(pc == 0x18)
4123 in_interrupt++;
4124
4125 if((breakpoint_value == 0) && (in_interrupt == 0))
4126 {
4127 debug_on();
4128 }
4129 else
4130
4131 if(in_interrupt == 0)
4132 breakpoint_value--;
4133
4134 if(in_interrupt && (pc == 0x13c))
4135 in_interrupt--;
4136
4137 break;
4138 }
bbba3209 4139
4140 default:
4141 break;
2823a4c8 4142 }
4143
4144 if((current_debug_state == STEP) ||
4145 (current_debug_state == STEP_RUN))
4146 {
4147 u32 key = 0;
4148
4149 SDL_LockMutex(sound_mutex);
4150 SDL_PauseAudio(1);
4151
4152 if(output_field >= num_output_fields)
4153 {
4154 output_field = 0;
4155 debug_screen_clear();
4156 }
4157
4158 if(thumb)
4159 print_thumb_instruction(cycles);
4160 else
4161 print_arm_instruction(cycles);
4162
4163 print_arm_registers();
4164 print_flags();
4165 print_stack();
4166
4167
4168 printf("%x instructions in, VCOUNT %d, cycles remaining: %d \n",
4169 instruction_count, io_registers[REG_VCOUNT], cycles);
4170
4171 debug_screen_update();
4172 output_field++;
4173
4174 if(current_debug_state != STEP_RUN)
4175 {
4176
4177#ifdef STDIO_DEBUG
4178 key = getchar();
4179#else
4180
4181 gui_action_type next_input = CURSOR_NONE;
4182 while(next_input == CURSOR_NONE)
4183 {
4184 next_input = get_gui_input();
4185
4186 switch(next_input)
4187 {
4188 case CURSOR_BACK:
4189 key = 'b';
4190 break;
4191
4192 case CURSOR_UP:
4193 key = 'r';
4194 break;
4195
4196 case CURSOR_EXIT:
4197 key = 'q';
4198 break;
4199
4200 default:
4201 key = 'n';
4202 break;
4203 }
4204 }
4205#endif
4206 }
4207
4208 switch(key)
4209 {
4210 case 'd':
4211 dump_translation_cache();
4212 break;
4213
4214 case 'z':
4215 debug_off(Z_BREAKPOINT);
4216 break;
4217
4218#ifdef STDIO_DEBUG
4219 case 'x':
4220 printf("break at PC (hex): ");
4221 scanf("%08x", &breakpoint_value);
4222 debug_off(PC_BREAKPOINT);
4223 break;
4224
4225 case 'c':
4226 printf("break after N instructions (hex): ");
4227 scanf("%08x", &breakpoint_value);
4228 breakpoint_value -= 1;
4229 debug_off(COUNTDOWN_BREAKPOINT);
4230 break;
4231
4232 case 'f':
4233 printf("break after N instructions, skip in IRQ (hex): ");
4234 scanf("%08x", &breakpoint_value);
4235 breakpoint_value -= 1;
4236 debug_off(COUNTDOWN_BREAKPOINT_C);
4237 break;
4238
4239 case 'g':
4240 printf("break after N instructions (since start): ");
4241 scanf("%d", &breakpoint_value);
4242 debug_off(COUNTDOWN_BREAKPOINT_B);
4243 break;
4244
4245 case 'v':
4246 printf("break at VCOUNT: ");
4247 scanf("%d", &breakpoint_value);
4248 debug_off(VCOUNT_BREAKPOINT);
4249 break;
4250#endif
4251
4252 case 's':
4253 current_debug_state = STEP_RUN;
4254 break;
4255
4256 case 'r':
4257 debug_off(RUN);
4258 break;
4259
4260 case 'b':
4261 debug_off(PC_BREAKPOINT);
4262 break;
4263
4264 case 't':
4265 global_cycles_per_instruction = 0;
4266 debug_off(RUN);
4267 break;
4268
4269 case 'a':
4270 {
bbba3209 4271 char current_savestate_filename[512];
2823a4c8 4272 u16 *current_screen = copy_screen();
4273 get_savestate_filename_noshot(savestate_slot,
4274 current_savestate_filename);
4275 save_state(current_savestate_filename, current_screen);
4276 free(current_screen);
4277 break;
4278 }
4279
4280 case 'q':
4281 quit();
4282 }
4283
4284 SDL_PauseAudio(0);
4285 SDL_UnlockMutex(sound_mutex);
4286 }
4287
4288 last_instruction = reg[REG_PC];
4289
4290 if(thumb)
4291 reg[REG_PC] = pc + 2;
4292 else
4293 reg[REG_PC] = pc + 4;
2823a4c8 4294}
4295
4296void set_cpu_mode(cpu_mode_type new_mode)
4297{
4298 u32 i;
4299 cpu_mode_type cpu_mode = reg[CPU_MODE];
4300
4301 if(cpu_mode != new_mode)
4302 {
4303 if(new_mode == MODE_FIQ)
4304 {
4305 for(i = 8; i < 15; i++)
4306 {
4307 reg_mode[cpu_mode][i - 8] = reg[i];
4308 }
4309 }
4310 else
4311 {
4312 reg_mode[cpu_mode][5] = reg[REG_SP];
4313 reg_mode[cpu_mode][6] = reg[REG_LR];
4314 }
4315
4316 if(cpu_mode == MODE_FIQ)
4317 {
4318 for(i = 8; i < 15; i++)
4319 {
4320 reg[i] = reg_mode[new_mode][i - 8];
4321 }
4322 }
4323 else
4324 {
4325 reg[REG_SP] = reg_mode[new_mode][5];
4326 reg[REG_LR] = reg_mode[new_mode][6];
4327 }
4328
4329 reg[CPU_MODE] = new_mode;
4330 }
4331}
4332
4333void raise_interrupt(irq_type irq_raised)
4334{
4335 // The specific IRQ must be enabled in IE, master IRQ enable must be on,
4336 // and it must be on in the flags.
4337 io_registers[REG_IF] |= irq_raised;
4338
4339 if((io_registers[REG_IE] & irq_raised) && io_registers[REG_IME] &&
4340 ((reg[REG_CPSR] & 0x80) == 0))
4341 {
4342 bios_read_protect = 0xe55ec002;
4343
4344 // Interrupt handler in BIOS
4345 reg_mode[MODE_IRQ][6] = reg[REG_PC] + 4;
4346 spsr[MODE_IRQ] = reg[REG_CPSR];
4347 reg[REG_CPSR] = 0xD2;
4348 reg[REG_PC] = 0x00000018;
4349
4350 bios_region_read_allow();
4351
4352 set_cpu_mode(MODE_IRQ);
4353 reg[CPU_HALT_STATE] = CPU_ACTIVE;
4354 reg[CHANGED_PC_STATUS] = 1;
4355 }
4356}
4357
bbba3209 4358void execute_arm(u32 cycles)
2823a4c8 4359{
4360 u32 pc = reg[REG_PC];
4361 u32 opcode;
4362 u32 condition;
4363 u32 n_flag, z_flag, c_flag, v_flag;
4364 u32 pc_region = (pc >> 15);
4365 u8 *pc_address_block = memory_map_read[pc_region];
4366 u32 new_pc_region;
4367 s32 cycles_remaining;
4368 u32 cycles_per_instruction = global_cycles_per_instruction;
4369 cpu_alert_type cpu_alert;
4370
4371 u32 old_pc;
4372
4373 if(pc_address_block == NULL)
4374 pc_address_block = load_gamepak_page(pc_region & 0x3FF);
4375
4376 while(1)
4377 {
4378 cycles_remaining = cycles;
4379 pc = reg[REG_PC];
4380 extract_flags();
4381
4382 if(reg[REG_CPSR] & 0x20)
4383 goto thumb_loop;
4384
4385 do
4386 {
4387 arm_loop:
4388
4389 collapse_flags();
4390 step_debug(pc, cycles_remaining);
4391 cycles_per_instruction = global_cycles_per_instruction;
4392
4393 old_pc = pc;
4394 execute_arm_instruction();
4395 cycles_remaining -= cycles_per_instruction;
4396 } while(cycles_remaining > 0);
4397
4398 collapse_flags();
4399 cycles = update_gba();
4400 continue;
4401
4402 do
4403 {
4404 thumb_loop:
4405
4406 collapse_flags();
4407 step_debug(pc, cycles_remaining);
4408
4409 old_pc = pc;
4410 execute_thumb_instruction();
4411 cycles_remaining -= cycles_per_instruction;
4412 } while(cycles_remaining > 0);
4413
4414 collapse_flags();
4415 cycles = update_gba();
4416 continue;
4417
4418 alert:
4419
4420 if(cpu_alert == CPU_ALERT_IRQ)
4421 {
4422 cycles = cycles_remaining;
4423 }
4424 else
4425 {
4426 collapse_flags();
4427
4428 while(reg[CPU_HALT_STATE] != CPU_ACTIVE)
4429 {
4430 cycles = update_gba();
4431 }
4432 }
4433 }
4434}
4435
4436void init_cpu()
4437{
4438 u32 i;
4439
4440 for(i = 0; i < 16; i++)
4441 {
4442 reg[i] = 0;
4443 }
4444
4445 reg[REG_SP] = 0x03007F00;
4446 reg[REG_PC] = 0x08000000;
4447 reg[REG_CPSR] = 0x0000001F;
4448 reg[CPU_HALT_STATE] = CPU_ACTIVE;
4449 reg[CPU_MODE] = MODE_USER;
4450 reg[CHANGED_PC_STATUS] = 0;
4451
4452 reg_mode[MODE_USER][5] = 0x03007F00;
4453 reg_mode[MODE_IRQ][5] = 0x03007FA0;
4454 reg_mode[MODE_FIQ][5] = 0x03007FA0;
4455 reg_mode[MODE_SUPERVISOR][5] = 0x03007FE0;
4456}
4457
4458void move_reg(u32 *new_reg)
4459{
4460 u32 i;
4461
4462 for(i = 0; i < 32; i++)
4463 {
4464 new_reg[i] = reg[i];
4465 }
4466
4467 reg = new_reg;
4468}
4469
4470
4471#define cpu_savestate_builder(type) \
4472void cpu_##type##_savestate(file_tag_type savestate_file) \
4473{ \
4474 file_##type(savestate_file, reg, 0x100); \
4475 file_##type##_array(savestate_file, spsr); \
4476 file_##type##_array(savestate_file, reg_mode); \
4477} \
4478
4479cpu_savestate_builder(read);
4480cpu_savestate_builder(write_mem);
4481