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 #ifndef ARM_EMIT_H
21 #define ARM_EMIT_H
22
23 #include "arm_codegen.h"
24
25 void generate_indirect_branch_arm(void);
26 u32 prepare_load_reg_pc(u32 scratch_reg, u32 reg_index, u32 pc_offset);
27 void generate_store_reg(u32 ireg, u32 reg_index);
28 void complete_store_reg_pc_flags(u32 scratch_reg, u32 reg_index);
29 u32 prepare_load_reg(u32 scratch_reg, u32 reg_index);
30 u32 prepare_store_reg(u32 scratch_reg, u32 reg_index);
31 void generate_load_reg(u32 ireg, u32 reg_index);
32 void complete_store_reg(u32 scratch_reg, u32 reg_index);
33 void complete_store_reg_pc_no_flags(u32 scratch_reg, u32 reg_index);
34
35 u32 arm_update_gba_arm(u32 pc);
36 u32 arm_update_gba_thumb(u32 pc);
37 u32 arm_update_gba_idle_arm(u32 pc);
38 u32 arm_update_gba_idle_thumb(u32 pc);
39
40 /* Although these are defined as a function, don't call them as
41 * such (jump to it instead) */
42 void arm_indirect_branch_arm(u32 address);
43 void arm_indirect_branch_thumb(u32 address);
44 void arm_indirect_branch_dual_arm(u32 address);
45 void arm_indirect_branch_dual_thumb(u32 address);
46
47 void execute_store_cpsr(u32 new_cpsr, u32 store_mask, u32 address);
48 u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address);
49 void execute_store_spsr(u32 new_cpsr, u32 store_mask);
50 u32 execute_read_spsr(void);
51 u32 execute_spsr_restore(u32 address);
52
53 void execute_swi_arm(u32 pc);
54 void execute_swi_thumb(u32 pc);
55
56 void execute_store_u32_safe(u32 address, u32 source);
57
58 #define write32(value) \
59 *((u32 *)translation_ptr) = value; \
60 translation_ptr += 4 \
61
62 #define arm_relative_offset(source, offset) \
63 (((((u32)offset - (u32)source) - 8) >> 2) & 0xFFFFFF) \
64
65
66 /* reg_base_offset is the amount of bytes after reg_base where the registers
67 * actually begin. */
68
69 #define reg_base_offset 1024
70
71
72 #define reg_a0 ARMREG_R0
73 #define reg_a1 ARMREG_R1
74 #define reg_a2 ARMREG_R2
75
76 #define reg_s0 ARMREG_R9
77 #define reg_base ARMREG_SP
78 #define reg_flags ARMREG_R11
79
80 #define reg_cycles ARMREG_R12
81
82 #define reg_rv ARMREG_R0
83
84 #define reg_rm ARMREG_R0
85 #define reg_rn ARMREG_R1
86 #define reg_rs ARMREG_R14
87 #define reg_rd ARMREG_R0
88
89
90 /* Register allocation layout for ARM and Thumb:
91 * Map from a GBA register to a host ARM register. -1 means load it
92 * from memory into one of the temp registers.
93
94 * The following registers are chosen based on statistical analysis
95 * of a few games (see below), but might not be the best ones. Results
96 * vary tremendously between ARM and Thumb (for obvious reasons), so
97 * two sets are used. Take care to not call any function which can
98 * overwrite any of these registers from the dynarec - only call
99 * trusted functions in arm_stub.S which know how to save/restore
100 * them and know how to transfer them to the C functions it calls
101 * if necessary.
102
103 * The following define the actual registers available for allocation.
104 * As registers are freed up add them to this list.
105
106 * Note that r15 is linked to the a0 temp reg - this register will
107 * be preloaded with a constant upon read, and used to link to
108 * indirect branch functions upon write.
109 */
110
111 #define reg_x0 ARMREG_R3
112 #define reg_x1 ARMREG_R4
113 #define reg_x2 ARMREG_R5
114 #define reg_x3 ARMREG_R6
115 #define reg_x4 ARMREG_R7
116 #define reg_x5 ARMREG_R8
117
118 #define mem_reg (~0U)
119
120 /*
121
122 ARM register usage (38.775138% ARM instructions):
123 r00: 18.263814% (-- 18.263814%)
124 r12: 11.531477% (-- 29.795291%)
125 r09: 11.500162% (-- 41.295453%)
126 r14: 9.063440% (-- 50.358893%)
127 r06: 7.837682% (-- 58.196574%)
128 r01: 7.401049% (-- 65.597623%)
129 r07: 6.778340% (-- 72.375963%)
130 r05: 5.445009% (-- 77.820973%)
131 r02: 5.427288% (-- 83.248260%)
132 r03: 5.293743% (-- 88.542003%)
133 r04: 3.601103% (-- 92.143106%)
134 r11: 3.207311% (-- 95.350417%)
135 r10: 2.334864% (-- 97.685281%)
136 r08: 1.708207% (-- 99.393488%)
137 r15: 0.311270% (-- 99.704757%)
138 r13: 0.295243% (-- 100.000000%)
139
140 Thumb register usage (61.224862% Thumb instructions):
141 r00: 34.788858% (-- 34.788858%)
142 r01: 26.564083% (-- 61.352941%)
143 r03: 10.983500% (-- 72.336441%)
144 r02: 8.303127% (-- 80.639567%)
145 r04: 4.900381% (-- 85.539948%)
146 r05: 3.941292% (-- 89.481240%)
147 r06: 3.257582% (-- 92.738822%)
148 r07: 2.644851% (-- 95.383673%)
149 r13: 1.408824% (-- 96.792497%)
150 r08: 0.906433% (-- 97.698930%)
151 r09: 0.679693% (-- 98.378623%)
152 r10: 0.656446% (-- 99.035069%)
153 r12: 0.453668% (-- 99.488737%)
154 r14: 0.248909% (-- 99.737646%)
155 r11: 0.171066% (-- 99.908713%)
156 r15: 0.091287% (-- 100.000000%)
157
158 */
159
160 u32 arm_register_allocation[] =
161 {
162 reg_x0, /* GBA r0 */
163 reg_x1, /* GBA r1 */
164 mem_reg, /* GBA r2 */
165 mem_reg, /* GBA r3 */
166 mem_reg, /* GBA r4 */
167 mem_reg, /* GBA r5 */
168 reg_x2, /* GBA r6 */
169 mem_reg, /* GBA r7 */
170 mem_reg, /* GBA r8 */
171 reg_x3, /* GBA r9 */
172 mem_reg, /* GBA r10 */
173 mem_reg, /* GBA r11 */
174 reg_x4, /* GBA r12 */
175 mem_reg, /* GBA r13 */
176 reg_x5, /* GBA r14 */
177 reg_a0, /* GBA r15 */
178
179 mem_reg,
180 mem_reg,
181 mem_reg,
182 mem_reg,
183 mem_reg,
184 mem_reg,
185 mem_reg,
186 mem_reg,
187 mem_reg,
188 mem_reg,
189 mem_reg,
190 mem_reg,
191 mem_reg,
192 mem_reg,
193 mem_reg,
194 mem_reg,
195 };
196
197 u32 thumb_register_allocation[] =
198 {
199 reg_x0, /* GBA r0 */
200 reg_x1, /* GBA r1 */
201 reg_x2, /* GBA r2 */
202 reg_x3, /* GBA r3 */
203 reg_x4, /* GBA r4 */
204 reg_x5, /* GBA r5 */
205 mem_reg, /* GBA r6 */
206 mem_reg, /* GBA r7 */
207 mem_reg, /* GBA r8 */
208 mem_reg, /* GBA r9 */
209 mem_reg, /* GBA r10 */
210 mem_reg, /* GBA r11 */
211 mem_reg, /* GBA r12 */
212 mem_reg, /* GBA r13 */
213 mem_reg, /* GBA r14 */
214 reg_a0, /* GBA r15 */
215
216 mem_reg,
217 mem_reg,
218 mem_reg,
219 mem_reg,
220 mem_reg,
221 mem_reg,
222 mem_reg,
223 mem_reg,
224 mem_reg,
225 mem_reg,
226 mem_reg,
227 mem_reg,
228 mem_reg,
229 mem_reg,
230 mem_reg,
231 mem_reg,
232 };
233
234 #define arm_imm_lsl_to_rot(value) \
235 (32 - value) \
236
arm_disect_imm_32bit(u32 imm,u32 * stores,u32 * rotations)237 u32 arm_disect_imm_32bit(u32 imm, u32 *stores, u32 *rotations)
238 {
239 u32 store_count = 0;
240 u32 left_shift = 0;
241
242 /* Otherwise it'll return 0 things to store because it'll never
243 * find anything. */
244 if(imm == 0)
245 {
246 rotations[0] = 0;
247 stores[0] = 0;
248 return 1;
249 }
250
251 /* Find chunks of non-zero data at 2 bit alignments. */
252 while(1)
253 {
254 for(; left_shift < 32; left_shift += 2)
255 {
256 if((imm >> left_shift) & 0x03)
257 break;
258 }
259
260 /* We've hit the end of the useful data. */
261 if(left_shift == 32)
262 return store_count;
263
264 /* Hit the end, it might wrap back around to the beginning. */
265 if(left_shift >= 24)
266 {
267 /* Make a mask for the residual bits. IE, if we have
268 * 5 bits of data at the end we can wrap around to 3
269 * bits of data in the beginning. Thus the first
270 * thing, after being shifted left, has to be less
271 * than 111b, 0x7, or (1 << 3) - 1.
272 */
273 u32 top_bits = 32 - left_shift;
274 u32 residual_bits = 8 - top_bits;
275 u32 residual_mask = (1 << residual_bits) - 1;
276
277 if((store_count > 1) && (left_shift > 24) &&
278 ((stores[0] << ((32 - rotations[0]) & 0x1F)) < residual_mask))
279 {
280 /* Then we can throw out the last bit and tack it on
281 * to the first bit. */
282 stores[0] =
283 (stores[0] << ((top_bits + (32 - rotations[0])) & 0x1F)) |
284 ((imm >> left_shift) & 0xFF);
285 rotations[0] = top_bits;
286
287 return store_count;
288 }
289 else
290 {
291 /* There's nothing to wrap over to in the beginning */
292 stores[store_count] = (imm >> left_shift) & 0xFF;
293 rotations[store_count] = (32 - left_shift) & 0x1F;
294 return store_count + 1;
295 }
296 break;
297 }
298
299 stores[store_count] = (imm >> left_shift) & 0xFF;
300 rotations[store_count] = (32 - left_shift) & 0x1F;
301
302 store_count++;
303 left_shift += 8;
304 }
305 }
306
307 #define arm_load_imm_32bit(ireg, imm) \
308 { \
309 u32 stores[4]; \
310 u32 rotations[4]; \
311 u32 store_count = arm_disect_imm_32bit(imm, stores, rotations); \
312 u32 i; \
313 \
314 ARM_MOV_REG_IMM(0, ireg, stores[0], rotations[0]); \
315 \
316 for(i = 1; i < store_count; i++) \
317 { \
318 ARM_ORR_REG_IMM(0, ireg, ireg, stores[i], rotations[i]); \
319 } \
320 } \
321
322
323 #define generate_load_pc(ireg, new_pc) \
324 arm_load_imm_32bit(ireg, new_pc) \
325
326 #define generate_load_imm(ireg, imm, imm_ror) \
327 ARM_MOV_REG_IMM(0, ireg, imm, imm_ror) \
328
329
330
331 #define generate_shift_left(ireg, imm) \
332 ARM_MOV_REG_IMMSHIFT(0, ireg, ireg, ARMSHIFT_LSL, imm) \
333
334 #define generate_shift_right(ireg, imm) \
335 ARM_MOV_REG_IMMSHIFT(0, ireg, ireg, ARMSHIFT_LSR, imm) \
336
337 #define generate_shift_right_arithmetic(ireg, imm) \
338 ARM_MOV_REG_IMMSHIFT(0, ireg, ireg, ARMSHIFT_ASR, imm) \
339
340 #define generate_rotate_right(ireg, imm) \
341 ARM_MOV_REG_IMMSHIFT(0, ireg, ireg, ARMSHIFT_ROR, imm) \
342
343 #define generate_add(ireg_dest, ireg_src) \
344 ARM_ADD_REG_REG(0, ireg_dest, ireg_dest, ireg_src) \
345
346 #define generate_sub(ireg_dest, ireg_src) \
347 ARM_SUB_REG_REG(0, ireg_dest, ireg_dest, ireg_src) \
348
349 #define generate_or(ireg_dest, ireg_src) \
350 ARM_ORR_REG_REG(0, ireg_dest, ireg_dest, ireg_src) \
351
352 #define generate_xor(ireg_dest, ireg_src) \
353 ARM_EOR_REG_REG(0, ireg_dest, ireg_dest, ireg_src) \
354
355 #define generate_add_imm(ireg, imm, imm_ror) \
356 ARM_ADD_REG_IMM(0, ireg, ireg, imm, imm_ror) \
357
358 #define generate_sub_imm(ireg, imm, imm_ror) \
359 ARM_SUB_REG_IMM(0, ireg, ireg, imm, imm_ror) \
360
361 #define generate_xor_imm(ireg, imm, imm_ror) \
362 ARM_EOR_REG_IMM(0, ireg, ireg, imm, imm_ror) \
363
364 #define generate_add_reg_reg_imm(ireg_dest, ireg_src, imm, imm_ror) \
365 ARM_ADD_REG_IMM(0, ireg_dest, ireg_src, imm, imm_ror) \
366
367 #define generate_and_imm(ireg, imm, imm_ror) \
368 ARM_AND_REG_IMM(0, ireg, ireg, imm, imm_ror) \
369
370 #define generate_mov(ireg_dest, ireg_src) \
371 if(ireg_dest != ireg_src) \
372 { \
373 ARM_MOV_REG_REG(0, ireg_dest, ireg_src); \
374 } \
375
376 #define generate_function_call(function_location) \
377 ARM_BL(0, arm_relative_offset(translation_ptr, function_location)) \
378
379 #define generate_exit_block() \
380 ARM_BX(0, ARMREG_LR) \
381
382 /* The branch target is to be filled in later (thus a 0 for now) */
383
384 #define generate_branch_filler(condition_code, writeback_location) \
385 (writeback_location) = translation_ptr; \
386 ARM_B_COND(0, condition_code, 0) \
387
388 #define generate_update_pc(new_pc) \
389 generate_load_pc(reg_a0, new_pc) \
390
391 #define generate_cycle_update() \
392 if(cycle_count) \
393 { \
394 if(cycle_count >> 8) \
395 { \
396 ARM_ADD_REG_IMM(0, reg_cycles, reg_cycles, (cycle_count >> 8) & 0xFF, \
397 arm_imm_lsl_to_rot(8)); \
398 } \
399 ARM_ADD_REG_IMM(0, reg_cycles, reg_cycles, (cycle_count & 0xFF), 0); \
400 cycle_count = 0; \
401 } \
402
403 #define generate_cycle_update_flag_set() \
404 if(cycle_count >> 8) \
405 { \
406 ARM_ADD_REG_IMM(0, reg_cycles, reg_cycles, (cycle_count >> 8) & 0xFF, \
407 arm_imm_lsl_to_rot(8)); \
408 } \
409 generate_save_flags(); \
410 ARM_ADDS_REG_IMM(0, reg_cycles, reg_cycles, (cycle_count & 0xFF), 0); \
411 cycle_count = 0 \
412
413 #define generate_branch_patch_conditional(dest, offset) \
414 *((u32 *)(dest)) = (*((u32 *)dest) & 0xFF000000) | \
415 arm_relative_offset(dest, offset) \
416
417
418 #define generate_branch_patch_unconditional(dest, offset) \
419 *((u32 *)(dest)) = (*((u32 *)dest) & 0xFF000000) | \
420 arm_relative_offset(dest, offset) \
421
422 /* A different function is called for idle updates because of the relative
423 * location of the embedded PC. The idle version could be optimized to put
424 * the CPU into halt mode too, however.
425 */
426
427 #define generate_branch_idle_eliminate(writeback_location, new_pc, mode) \
428 generate_function_call(arm_update_gba_idle_##mode); \
429 write32(new_pc); \
430 generate_branch_filler(ARMCOND_AL, writeback_location) \
431
432 #define generate_branch_update(writeback_location, new_pc, mode) \
433 ARM_MOV_REG_IMMSHIFT(0, reg_a0, reg_cycles, ARMSHIFT_LSR, 31); \
434 ARM_ADD_REG_IMMSHIFT(0, ARMREG_PC, ARMREG_PC, reg_a0, ARMSHIFT_LSL, 2); \
435 write32(new_pc); \
436 generate_function_call(arm_update_gba_##mode); \
437 generate_branch_filler(ARMCOND_AL, writeback_location) \
438
439
440 #define generate_branch_no_cycle_update(writeback_location, new_pc, mode) \
441 if(pc == idle_loop_target_pc) \
442 { \
443 generate_branch_idle_eliminate(writeback_location, new_pc, mode); \
444 } \
445 else \
446 { \
447 generate_branch_update(writeback_location, new_pc, mode); \
448 } \
449
450 #define generate_branch_cycle_update(writeback_location, new_pc, mode) \
451 generate_cycle_update(); \
452 generate_branch_no_cycle_update(writeback_location, new_pc, mode) \
453
454 /* a0 holds the destination */
455
456 #define generate_indirect_branch_no_cycle_update(type) \
457 ARM_B(0, arm_relative_offset(translation_ptr, arm_indirect_branch_##type)) \
458
459 #define generate_indirect_branch_cycle_update(type) \
460 generate_cycle_update(); \
461 generate_indirect_branch_no_cycle_update(type) \
462
463 #define generate_block_prologue() \
464
465 #define generate_block_extra_vars_arm() \
466 void generate_indirect_branch_arm(void) \
467 { \
468 if(condition == 0x0E) \
469 { \
470 generate_cycle_update(); \
471 } \
472 generate_indirect_branch_no_cycle_update(arm); \
473 } \
474 \
475 void generate_indirect_branch_dual() \
476 { \
477 if(condition == 0x0E) \
478 { \
479 generate_cycle_update(); \
480 } \
481 generate_indirect_branch_no_cycle_update(dual_arm); \
482 } \
483 \
484 u32 prepare_load_reg(u32 scratch_reg, u32 reg_index) \
485 { \
486 u32 reg_use = arm_register_allocation[reg_index]; \
487 if(reg_use == mem_reg) \
488 { \
489 ARM_LDR_IMM(0, scratch_reg, reg_base, \
490 (reg_base_offset + (reg_index * 4))); \
491 return scratch_reg; \
492 } \
493 \
494 return reg_use; \
495 } \
496 \
497 u32 prepare_load_reg_pc(u32 scratch_reg, u32 reg_index, u32 pc_offset) \
498 { \
499 if(reg_index == 15) \
500 { \
501 generate_load_pc(scratch_reg, pc + pc_offset); \
502 return scratch_reg; \
503 } \
504 return prepare_load_reg(scratch_reg, reg_index); \
505 } \
506 \
507 u32 prepare_store_reg(u32 scratch_reg, u32 reg_index) \
508 { \
509 u32 reg_use = arm_register_allocation[reg_index]; \
510 if(reg_use == mem_reg) \
511 return scratch_reg; \
512 \
513 return reg_use; \
514 } \
515 \
516 void complete_store_reg(u32 scratch_reg, u32 reg_index) \
517 { \
518 if(arm_register_allocation[reg_index] == mem_reg) \
519 { \
520 ARM_STR_IMM(0, scratch_reg, reg_base, \
521 (reg_base_offset + (reg_index * 4))); \
522 } \
523 } \
524 \
525 void complete_store_reg_pc_no_flags(u32 scratch_reg, u32 reg_index) \
526 { \
527 if(reg_index == 15) \
528 { \
529 generate_indirect_branch_arm(); \
530 } \
531 else \
532 { \
533 complete_store_reg(scratch_reg, reg_index); \
534 } \
535 } \
536 \
537 void complete_store_reg_pc_flags(u32 scratch_reg, u32 reg_index) \
538 { \
539 if(reg_index == 15) \
540 { \
541 if(condition == 0x0E) \
542 { \
543 generate_cycle_update(); \
544 } \
545 generate_function_call(execute_spsr_restore); \
546 } \
547 else \
548 { \
549 complete_store_reg(scratch_reg, reg_index); \
550 } \
551 } \
552 \
553 void generate_load_reg(u32 ireg, u32 reg_index) \
554 { \
555 u32 load_src = arm_register_allocation[reg_index]; \
556 if(load_src != mem_reg) \
557 { \
558 ARM_MOV_REG_REG(0, ireg, load_src); \
559 } \
560 else \
561 { \
562 ARM_LDR_IMM(0, ireg, reg_base, (reg_base_offset + (reg_index * 4))); \
563 } \
564 } \
565 \
566 void generate_store_reg(u32 ireg, u32 reg_index) \
567 { \
568 u32 store_dest = arm_register_allocation[reg_index]; \
569 if(store_dest != mem_reg) \
570 { \
571 ARM_MOV_REG_REG(0, store_dest, ireg); \
572 } \
573 else \
574 { \
575 ARM_STR_IMM(0, ireg, reg_base, (reg_base_offset + (reg_index * 4))); \
576 } \
577 } \
578
579
580 #define generate_block_extra_vars_thumb() \
581 u32 prepare_load_reg(u32 scratch_reg, u32 reg_index) \
582 { \
583 u32 reg_use = thumb_register_allocation[reg_index]; \
584 if(reg_use == mem_reg) \
585 { \
586 ARM_LDR_IMM(0, scratch_reg, reg_base, \
587 (reg_base_offset + (reg_index * 4))); \
588 return scratch_reg; \
589 } \
590 \
591 return reg_use; \
592 } \
593 \
594 u32 prepare_load_reg_pc(u32 scratch_reg, u32 reg_index, u32 pc_offset) \
595 { \
596 if(reg_index == 15) \
597 { \
598 generate_load_pc(scratch_reg, pc + pc_offset); \
599 return scratch_reg; \
600 } \
601 return prepare_load_reg(scratch_reg, reg_index); \
602 } \
603 \
604 u32 prepare_store_reg(u32 scratch_reg, u32 reg_index) \
605 { \
606 u32 reg_use = thumb_register_allocation[reg_index]; \
607 if(reg_use == mem_reg) \
608 return scratch_reg; \
609 \
610 return reg_use; \
611 } \
612 \
613 void complete_store_reg(u32 scratch_reg, u32 reg_index) \
614 { \
615 if(thumb_register_allocation[reg_index] == mem_reg) \
616 { \
617 ARM_STR_IMM(0, scratch_reg, reg_base, \
618 (reg_base_offset + (reg_index * 4))); \
619 } \
620 } \
621 \
622 void generate_load_reg(u32 ireg, u32 reg_index) \
623 { \
624 u32 load_src = thumb_register_allocation[reg_index]; \
625 if(load_src != mem_reg) \
626 { \
627 ARM_MOV_REG_REG(0, ireg, load_src); \
628 } \
629 else \
630 { \
631 ARM_LDR_IMM(0, ireg, reg_base, (reg_base_offset + (reg_index * 4))); \
632 } \
633 } \
634 \
635 void generate_store_reg(u32 ireg, u32 reg_index) \
636 { \
637 u32 store_dest = thumb_register_allocation[reg_index]; \
638 if(store_dest != mem_reg) \
639 { \
640 ARM_MOV_REG_REG(0, store_dest, ireg); \
641 } \
642 else \
643 { \
644 ARM_STR_IMM(0, ireg, reg_base, (reg_base_offset + (reg_index * 4))); \
645 } \
646 } \
647
648 #define block_prologue_size 0
649
650 /* It should be okay to still generate result flags, spsr will overwrite them.
651 * This is pretty infrequent (returning from interrupt handlers, et al) so
652 * probably not worth optimizing for.
653 */
654
655 #define check_for_interrupts() \
656 if((io_registers[REG_IE] & io_registers[REG_IF]) && \
657 io_registers[REG_IME] && ((reg[REG_CPSR] & 0x80) == 0)) \
658 { \
659 reg_mode[MODE_IRQ][6] = pc + 4; \
660 spsr[MODE_IRQ] = reg[REG_CPSR]; \
661 reg[REG_CPSR] = 0xD2; \
662 pc = 0x00000018; \
663 set_cpu_mode(MODE_IRQ); \
664 } \
665
666 #define generate_load_reg_pc(ireg, reg_index, pc_offset) \
667 if(reg_index == 15) \
668 { \
669 generate_load_pc(ireg, pc + pc_offset); \
670 } \
671 else \
672 { \
673 generate_load_reg(ireg, reg_index); \
674 } \
675
676 #define generate_store_reg_pc_no_flags(ireg, reg_index) \
677 generate_store_reg(ireg, reg_index); \
678 if(reg_index == 15) \
679 { \
680 generate_indirect_branch_arm(); \
681 } \
682
683
execute_spsr_restore_body(u32 pc)684 u32 execute_spsr_restore_body(u32 pc)
685 {
686 set_cpu_mode(cpu_modes[reg[REG_CPSR] & 0x1F]);
687 check_for_interrupts();
688
689 return pc;
690 }
691
692
693 #define generate_store_reg_pc_flags(ireg, reg_index) \
694 generate_store_reg(ireg, reg_index); \
695 if(reg_index == 15) \
696 { \
697 if(condition == 0x0E) \
698 { \
699 generate_cycle_update(); \
700 } \
701 generate_function_call(execute_spsr_restore); \
702 } \
703
704
705 #define generate_load_flags() \
706 /* ARM_MSR_REG(0, ARM_PSR_F, reg_flags, ARM_CPSR) */ \
707
708 #define generate_store_flags() \
709 /* ARM_MRS_CPSR(0, reg_flags) */ \
710
711 #define generate_save_flags() \
712 ARM_MRS_CPSR(0, reg_flags) \
713
714 #define generate_restore_flags() \
715 ARM_MSR_REG(0, ARM_PSR_F, reg_flags, ARM_CPSR) \
716
717
718 #define condition_opposite_eq ARMCOND_NE
719 #define condition_opposite_ne ARMCOND_EQ
720 #define condition_opposite_cs ARMCOND_CC
721 #define condition_opposite_cc ARMCOND_CS
722 #define condition_opposite_mi ARMCOND_PL
723 #define condition_opposite_pl ARMCOND_MI
724 #define condition_opposite_vs ARMCOND_VC
725 #define condition_opposite_vc ARMCOND_VS
726 #define condition_opposite_hi ARMCOND_LS
727 #define condition_opposite_ls ARMCOND_HI
728 #define condition_opposite_ge ARMCOND_LT
729 #define condition_opposite_lt ARMCOND_GE
730 #define condition_opposite_gt ARMCOND_LE
731 #define condition_opposite_le ARMCOND_GT
732 #define condition_opposite_al ARMCOND_NV
733 #define condition_opposite_nv ARMCOND_AL
734
735 #define generate_branch(mode) \
736 { \
737 generate_branch_cycle_update( \
738 block_exits[block_exit_position].branch_source, \
739 block_exits[block_exit_position].branch_target, mode); \
740 block_exit_position++; \
741 } \
742
743
744 #define generate_op_and_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
745 ARM_AND_REG_IMMSHIFT(0, _rd, _rn, _rm, shift_type, shift) \
746
747 #define generate_op_orr_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
748 ARM_ORR_REG_IMMSHIFT(0, _rd, _rn, _rm, shift_type, shift) \
749
750 #define generate_op_eor_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
751 ARM_EOR_REG_IMMSHIFT(0, _rd, _rn, _rm, shift_type, shift) \
752
753 #define generate_op_bic_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
754 ARM_BIC_REG_IMMSHIFT(0, _rd, _rn, _rm, shift_type, shift) \
755
756 #define generate_op_sub_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
757 ARM_SUB_REG_IMMSHIFT(0, _rd, _rn, _rm, shift_type, shift) \
758
759 #define generate_op_rsb_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
760 ARM_RSB_REG_IMMSHIFT(0, _rd, _rn, _rm, shift_type, shift) \
761
762 #define generate_op_sbc_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
763 ARM_SBC_REG_IMMSHIFT(0, _rd, _rn, _rm, shift_type, shift) \
764
765 #define generate_op_rsc_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
766 ARM_RSC_REG_IMMSHIFT(0, _rd, _rn, _rm, shift_type, shift) \
767
768 #define generate_op_add_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
769 ARM_ADD_REG_IMMSHIFT(0, _rd, _rn, _rm, shift_type, shift) \
770
771 #define generate_op_adc_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
772 ARM_ADC_REG_IMMSHIFT(0, _rd, _rn, _rm, shift_type, shift) \
773
774 #define generate_op_mov_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
775 ARM_MOV_REG_IMMSHIFT(0, _rd, _rm, shift_type, shift) \
776
777 #define generate_op_mvn_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
778 ARM_MVN_REG_IMMSHIFT(0, _rd, _rm, shift_type, shift) \
779
780
781 #define generate_op_and_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
782 ARM_AND_REG_REGSHIFT(0, _rd, _rn, _rm, shift_type, _rs) \
783
784 #define generate_op_orr_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
785 ARM_ORR_REG_REGSHIFT(0, _rd, _rn, _rm, shift_type, _rs) \
786
787 #define generate_op_eor_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
788 ARM_EOR_REG_REGSHIFT(0, _rd, _rn, _rm, shift_type, _rs) \
789
790 #define generate_op_bic_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
791 ARM_BIC_REG_REGSHIFT(0, _rd, _rn, _rm, shift_type, _rs) \
792
793 #define generate_op_sub_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
794 ARM_SUB_REG_REGSHIFT(0, _rd, _rn, _rm, shift_type, _rs) \
795
796 #define generate_op_rsb_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
797 ARM_RSB_REG_REGSHIFT(0, _rd, _rn, _rm, shift_type, _rs) \
798
799 #define generate_op_sbc_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
800 ARM_SBC_REG_REGSHIFT(0, _rd, _rn, _rm, shift_type, _rs) \
801
802 #define generate_op_rsc_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
803 ARM_RSC_REG_REGSHIFT(0, _rd, _rn, _rm, shift_type, _rs) \
804
805 #define generate_op_add_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
806 ARM_ADD_REG_REGSHIFT(0, _rd, _rn, _rm, shift_type, _rs) \
807
808 #define generate_op_adc_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
809 ARM_ADC_REG_REGSHIFT(0, _rd, _rn, _rm, shift_type, _rs) \
810
811 #define generate_op_mov_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
812 ARM_MOV_REG_REGSHIFT(0, _rd, _rm, shift_type, _rs) \
813
814 #define generate_op_mvn_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
815 ARM_MVN_REG_REGSHIFT(0, _rd, _rm, shift_type, _rs) \
816
817
818 #define generate_op_and_imm(_rd, _rn) \
819 ARM_AND_REG_IMM(0, _rd, _rn, imm, imm_ror) \
820
821 #define generate_op_orr_imm(_rd, _rn) \
822 ARM_ORR_REG_IMM(0, _rd, _rn, imm, imm_ror) \
823
824 #define generate_op_eor_imm(_rd, _rn) \
825 ARM_EOR_REG_IMM(0, _rd, _rn, imm, imm_ror) \
826
827 #define generate_op_bic_imm(_rd, _rn) \
828 ARM_BIC_REG_IMM(0, _rd, _rn, imm, imm_ror) \
829
830 #define generate_op_sub_imm(_rd, _rn) \
831 ARM_SUB_REG_IMM(0, _rd, _rn, imm, imm_ror) \
832
833 #define generate_op_rsb_imm(_rd, _rn) \
834 ARM_RSB_REG_IMM(0, _rd, _rn, imm, imm_ror) \
835
836 #define generate_op_sbc_imm(_rd, _rn) \
837 ARM_SBC_REG_IMM(0, _rd, _rn, imm, imm_ror) \
838
839 #define generate_op_rsc_imm(_rd, _rn) \
840 ARM_RSC_REG_IMM(0, _rd, _rn, imm, imm_ror) \
841
842 #define generate_op_add_imm(_rd, _rn) \
843 ARM_ADD_REG_IMM(0, _rd, _rn, imm, imm_ror) \
844
845 #define generate_op_adc_imm(_rd, _rn) \
846 ARM_ADC_REG_IMM(0, _rd, _rn, imm, imm_ror) \
847
848 #define generate_op_mov_imm(_rd, _rn) \
849 ARM_MOV_REG_IMM(0, _rd, imm, imm_ror) \
850
851 #define generate_op_mvn_imm(_rd, _rn) \
852 ARM_MVN_REG_IMM(0, _rd, imm, imm_ror) \
853
854
855 #define generate_op_reg_immshift_lflags(name, _rd, _rn, _rm, st, shift) \
856 ARM_##name##_REG_IMMSHIFT(0, _rd, _rn, _rm, st, shift) \
857
858 #define generate_op_reg_immshift_aflags(name, _rd, _rn, _rm, st, shift) \
859 ARM_##name##_REG_IMMSHIFT(0, _rd, _rn, _rm, st, shift) \
860
861 #define generate_op_reg_immshift_aflags_load_c(name, _rd, _rn, _rm, st, sh) \
862 ARM_##name##_REG_IMMSHIFT(0, _rd, _rn, _rm, st, sh) \
863
864 #define generate_op_reg_immshift_uflags(name, _rd, _rm, shift_type, shift) \
865 ARM_##name##_REG_IMMSHIFT(0, _rd, _rm, shift_type, shift) \
866
867 #define generate_op_reg_immshift_tflags(name, _rn, _rm, shift_type, shift) \
868 ARM_##name##_REG_IMMSHIFT(0, _rn, _rm, shift_type, shift) \
869
870
871 #define generate_op_reg_regshift_lflags(name, _rd, _rn, _rm, shift_type, _rs) \
872 ARM_##name##_REG_REGSHIFT(0, _rd, _rn, _rm, shift_type, _rs) \
873
874 #define generate_op_reg_regshift_aflags(name, _rd, _rn, _rm, st, _rs) \
875 ARM_##name##_REG_REGSHIFT(0, _rd, _rn, _rm, st, _rs) \
876
877 #define generate_op_reg_regshift_aflags_load_c(name, _rd, _rn, _rm, st, _rs) \
878 ARM_##name##_REG_REGSHIFT(0, _rd, _rn, _rm, st, _rs) \
879
880 #define generate_op_reg_regshift_uflags(name, _rd, _rm, shift_type, _rs) \
881 ARM_##name##_REG_REGSHIFT(0, _rd, _rm, shift_type, _rs) \
882
883 #define generate_op_reg_regshift_tflags(name, _rn, _rm, shift_type, _rs) \
884 ARM_##name##_REG_REGSHIFT(0, _rn, _rm, shift_type, _rs) \
885
886
887 #define generate_op_imm_lflags(name, _rd, _rn) \
888 ARM_##name##_REG_IMM(0, _rd, _rn, imm, imm_ror) \
889
890 #define generate_op_imm_aflags(name, _rd, _rn) \
891 ARM_##name##_REG_IMM(0, _rd, _rn, imm, imm_ror) \
892
893 #define generate_op_imm_aflags_load_c(name, _rd, _rn) \
894 ARM_##name##_REG_IMM(0, _rd, _rn, imm, imm_ror) \
895
896 #define generate_op_imm_uflags(name, _rd) \
897 ARM_##name##_REG_IMM(0, _rd, imm, imm_ror) \
898
899 #define generate_op_imm_tflags(name, _rn) \
900 ARM_##name##_REG_IMM(0, _rn, imm, imm_ror) \
901
902
903 #define generate_op_ands_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
904 generate_op_reg_immshift_lflags(ANDS, _rd, _rn, _rm, shift_type, shift) \
905
906 #define generate_op_orrs_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
907 generate_op_reg_immshift_lflags(ORRS, _rd, _rn, _rm, shift_type, shift) \
908
909 #define generate_op_eors_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
910 generate_op_reg_immshift_lflags(EORS, _rd, _rn, _rm, shift_type, shift) \
911
912 #define generate_op_bics_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
913 generate_op_reg_immshift_lflags(BICS, _rd, _rn, _rm, shift_type, shift) \
914
915 #define generate_op_subs_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
916 generate_op_reg_immshift_aflags(SUBS, _rd, _rn, _rm, shift_type, shift) \
917
918 #define generate_op_rsbs_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
919 generate_op_reg_immshift_aflags(RSBS, _rd, _rn, _rm, shift_type, shift) \
920
921 #define generate_op_sbcs_reg_immshift(_rd, _rn, _rm, st, shift) \
922 generate_op_reg_immshift_aflags_load_c(SBCS, _rd, _rn, _rm, st, shift) \
923
924 #define generate_op_rscs_reg_immshift(_rd, _rn, _rm, st, shift) \
925 generate_op_reg_immshift_aflags_load_c(RSCS, _rd, _rn, _rm, st, shift) \
926
927 #define generate_op_adds_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
928 generate_op_reg_immshift_aflags(ADDS, _rd, _rn, _rm, shift_type, shift) \
929
930 #define generate_op_adcs_reg_immshift(_rd, _rn, _rm, st, shift) \
931 generate_op_reg_immshift_aflags_load_c(ADCS, _rd, _rn, _rm, st, shift) \
932
933 #define generate_op_movs_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
934 generate_op_reg_immshift_uflags(MOVS, _rd, _rm, shift_type, shift) \
935
936 #define generate_op_mvns_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
937 generate_op_reg_immshift_uflags(MVNS, _rd, _rm, shift_type, shift) \
938
939 /* The reg operand is in reg_rm, not reg_rn like expected, so rsbs isn't
940 * being used here. When rsbs is fully inlined it can be used with the
941 * apropriate operands.
942 */
943
944 #define generate_op_neg_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
945 { \
946 generate_load_imm(reg_rn, 0, 0); \
947 generate_op_subs_reg_immshift(_rd, reg_rn, _rm, ARMSHIFT_LSL, 0); \
948 } \
949
950 #define generate_op_muls_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
951 generate_load_flags(); \
952 ARM_MULS(0, _rd, _rn, _rm); \
953 generate_store_flags() \
954
955 #define generate_op_cmp_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
956 generate_op_reg_immshift_tflags(CMP, _rn, _rm, shift_type, shift) \
957
958 #define generate_op_cmn_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
959 generate_op_reg_immshift_tflags(CMN, _rn, _rm, shift_type, shift) \
960
961 #define generate_op_tst_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
962 generate_op_reg_immshift_tflags(TST, _rn, _rm, shift_type, shift) \
963
964 #define generate_op_teq_reg_immshift(_rd, _rn, _rm, shift_type, shift) \
965 generate_op_reg_immshift_tflags(TEQ, _rn, _rm, shift_type, shift) \
966
967
968 #define generate_op_ands_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
969 generate_op_reg_regshift_lflags(ANDS, _rd, _rn, _rm, shift_type, _rs) \
970
971 #define generate_op_orrs_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
972 generate_op_reg_regshift_lflags(ORRS, _rd, _rn, _rm, shift_type, _rs) \
973
974 #define generate_op_eors_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
975 generate_op_reg_regshift_lflags(EORS, _rd, _rn, _rm, shift_type, _rs) \
976
977 #define generate_op_bics_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
978 generate_op_reg_regshift_lflags(BICS, _rd, _rn, _rm, shift_type, _rs) \
979
980 #define generate_op_subs_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
981 generate_op_reg_regshift_aflags(SUBS, _rd, _rn, _rm, shift_type, _rs) \
982
983 #define generate_op_rsbs_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
984 generate_op_reg_regshift_aflags(RSBS, _rd, _rn, _rm, shift_type, _rs) \
985
986 #define generate_op_sbcs_reg_regshift(_rd, _rn, _rm, st, _rs) \
987 generate_op_reg_regshift_aflags_load_c(SBCS, _rd, _rn, _rm, st, _rs) \
988
989 #define generate_op_rscs_reg_regshift(_rd, _rn, _rm, st, _rs) \
990 generate_op_reg_regshift_aflags_load_c(RSCS, _rd, _rn, _rm, st, _rs) \
991
992 #define generate_op_adds_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
993 generate_op_reg_regshift_aflags(ADDS, _rd, _rn, _rm, shift_type, _rs) \
994
995 #define generate_op_adcs_reg_regshift(_rd, _rn, _rm, st, _rs) \
996 generate_op_reg_regshift_aflags_load_c(ADCS, _rd, _rn, _rm, st, _rs) \
997
998 #define generate_op_movs_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
999 generate_op_reg_regshift_uflags(MOVS, _rd, _rm, shift_type, _rs) \
1000
1001 #define generate_op_mvns_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
1002 generate_op_reg_regshift_uflags(MVNS, _rd, _rm, shift_type, _rs) \
1003
1004 #define generate_op_cmp_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
1005 generate_op_reg_regshift_tflags(CMP, _rn, _rm, shift_type, _rs) \
1006
1007 #define generate_op_cmn_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
1008 generate_op_reg_regshift_tflags(CMN, _rn, _rm, shift_type, _rs) \
1009
1010 #define generate_op_tst_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
1011 generate_op_reg_regshift_tflags(TST, _rn, _rm, shift_type, _rs) \
1012
1013 #define generate_op_teq_reg_regshift(_rd, _rn, _rm, shift_type, _rs) \
1014 generate_op_reg_regshift_tflags(TEQ, _rn, _rm, shift_type, _rs) \
1015
1016
1017 #define generate_op_ands_imm(_rd, _rn) \
1018 generate_op_imm_lflags(ANDS, _rd, _rn) \
1019
1020 #define generate_op_orrs_imm(_rd, _rn) \
1021 generate_op_imm_lflags(ORRS, _rd, _rn) \
1022
1023 #define generate_op_eors_imm(_rd, _rn) \
1024 generate_op_imm_lflags(EORS, _rd, _rn) \
1025
1026 #define generate_op_bics_imm(_rd, _rn) \
1027 generate_op_imm_lflags(BICS, _rd, _rn) \
1028
1029 #define generate_op_subs_imm(_rd, _rn) \
1030 generate_op_imm_aflags(SUBS, _rd, _rn) \
1031
1032 #define generate_op_rsbs_imm(_rd, _rn) \
1033 generate_op_imm_aflags(RSBS, _rd, _rn) \
1034
1035 #define generate_op_sbcs_imm(_rd, _rn) \
1036 generate_op_imm_aflags_load_c(SBCS, _rd, _rn) \
1037
1038 #define generate_op_rscs_imm(_rd, _rn) \
1039 generate_op_imm_aflags_load_c(RSCS, _rd, _rn) \
1040
1041 #define generate_op_adds_imm(_rd, _rn) \
1042 generate_op_imm_aflags(ADDS, _rd, _rn) \
1043
1044 #define generate_op_adcs_imm(_rd, _rn) \
1045 generate_op_imm_aflags_load_c(ADCS, _rd, _rn) \
1046
1047 #define generate_op_movs_imm(_rd, _rn) \
1048 generate_op_imm_uflags(MOVS, _rd) \
1049
1050 #define generate_op_mvns_imm(_rd, _rn) \
1051 generate_op_imm_uflags(MVNS, _rd) \
1052
1053 #define generate_op_cmp_imm(_rd, _rn) \
1054 generate_op_imm_tflags(CMP, _rn) \
1055
1056 #define generate_op_cmn_imm(_rd, _rn) \
1057 generate_op_imm_tflags(CMN, _rn) \
1058
1059 #define generate_op_tst_imm(_rd, _rn) \
1060 generate_op_imm_tflags(TST, _rn) \
1061
1062 #define generate_op_teq_imm(_rd, _rn) \
1063 generate_op_imm_tflags(TEQ, _rn) \
1064
1065
1066 #define prepare_load_rn_yes() \
1067 u32 _rn = prepare_load_reg_pc(reg_rn, rn, 8) \
1068
1069 #define prepare_load_rn_no() \
1070
1071 #define prepare_store_rd_yes() \
1072 u32 _rd = prepare_store_reg(reg_rd, rd) \
1073
1074 #define prepare_store_rd_no() \
1075
1076 #define complete_store_rd_yes(flags_op) \
1077 complete_store_reg_pc_##flags_op(_rd, rd) \
1078
1079 #define complete_store_rd_no(flags_op) \
1080
1081 #define arm_generate_op_reg(name, load_op, store_op, flags_op) \
1082 u32 shift_type = (opcode >> 5) & 0x03; \
1083 arm_decode_data_proc_reg(opcode); \
1084 prepare_load_rn_##load_op(); \
1085 prepare_store_rd_##store_op(); \
1086 \
1087 if((opcode >> 4) & 0x01) \
1088 { \
1089 u32 rs = ((opcode >> 8) & 0x0F); \
1090 u32 _rs = prepare_load_reg(reg_rs, rs); \
1091 u32 _rm = prepare_load_reg_pc(reg_rm, rm, 12); \
1092 generate_op_##name##_reg_regshift(_rd, _rn, _rm, shift_type, _rs); \
1093 } \
1094 else \
1095 { \
1096 u32 shift_imm = ((opcode >> 7) & 0x1F); \
1097 u32 _rm = prepare_load_reg_pc(reg_rm, rm, 8); \
1098 generate_op_##name##_reg_immshift(_rd, _rn, _rm, shift_type, shift_imm); \
1099 } \
1100 complete_store_rd_##store_op(flags_op) \
1101
1102 #define arm_generate_op_reg_flags(name, load_op, store_op, flags_op) \
1103 arm_generate_op_reg(name, load_op, store_op, flags_op) \
1104
1105 /* imm will be loaded by the called function if necessary. */
1106
1107 #define arm_generate_op_imm(name, load_op, store_op, flags_op) \
1108 arm_decode_data_proc_imm(opcode); \
1109 prepare_load_rn_##load_op(); \
1110 prepare_store_rd_##store_op(); \
1111 generate_op_##name##_imm(_rd, _rn); \
1112 complete_store_rd_##store_op(flags_op) \
1113
1114 #define arm_generate_op_imm_flags(name, load_op, store_op, flags_op) \
1115 arm_generate_op_imm(name, load_op, store_op, flags_op) \
1116
1117 #define arm_data_proc(name, type, flags_op) \
1118 { \
1119 arm_generate_op_##type(name, yes, yes, flags_op); \
1120 } \
1121
1122 #define arm_data_proc_test(name, type) \
1123 { \
1124 arm_generate_op_##type(name, yes, no, no); \
1125 } \
1126
1127 #define arm_data_proc_unary(name, type, flags_op) \
1128 { \
1129 arm_generate_op_##type(name, no, yes, flags_op); \
1130 } \
1131
1132
1133 #define arm_multiply_add_no_flags_no() \
1134 ARM_MUL(0, _rd, _rm, _rs) \
1135
1136 #define arm_multiply_add_yes_flags_no() \
1137 u32 _rn = prepare_load_reg(reg_a2, rn); \
1138 ARM_MLA(0, _rd, _rm, _rs, _rn) \
1139
1140 #define arm_multiply_add_no_flags_yes() \
1141 generate_load_flags(); \
1142 ARM_MULS(0, reg_a0, reg_a0, reg_a1) \
1143 generate_store_flags() \
1144
1145 #define arm_multiply_add_yes_flags_yes() \
1146 u32 _rn = prepare_load_reg(reg_a2, rn); \
1147 generate_load_flags(); \
1148 ARM_MLAS(0, _rd, _rm, _rs, _rn); \
1149 generate_store_flags()
1150
1151
1152 #define arm_multiply(add_op, flags) \
1153 { \
1154 arm_decode_multiply(); \
1155 u32 _rm = prepare_load_reg(reg_a0, rm); \
1156 u32 _rs = prepare_load_reg(reg_a1, rs); \
1157 u32 _rd = prepare_store_reg(reg_a0, rd); \
1158 arm_multiply_add_##add_op##_flags_##flags(); \
1159 complete_store_reg(_rd, rd); \
1160 } \
1161
1162
1163 #define arm_multiply_long_name_s64 SMULL
1164 #define arm_multiply_long_name_u64 UMULL
1165 #define arm_multiply_long_name_s64_add SMLAL
1166 #define arm_multiply_long_name_u64_add UMLAL
1167
1168
1169 #define arm_multiply_long_flags_no(name) \
1170 ARM_##name(0, _rdlo, _rdhi, _rm, _rs) \
1171
1172 #define arm_multiply_long_flags_yes(name) \
1173 generate_load_flags(); \
1174 ARM_##name##S(0, _rdlo, _rdhi, _rm, _rs); \
1175 generate_store_flags() \
1176
1177
1178 #define arm_multiply_long_add_no(name) \
1179
1180 #define arm_multiply_long_add_yes(name) \
1181 prepare_load_reg(reg_a0, rdlo); \
1182 prepare_load_reg(reg_a1, rdhi) \
1183
1184
1185 #define arm_multiply_long_op(flags, name) \
1186 arm_multiply_long_flags_##flags(name) \
1187
1188 #define arm_multiply_long(name, add_op, flags) \
1189 { \
1190 arm_decode_multiply_long(); \
1191 u32 _rm = prepare_load_reg(reg_a2, rm); \
1192 u32 _rs = prepare_load_reg(reg_rs, rs); \
1193 u32 _rdlo = prepare_store_reg(reg_a0, rdlo); \
1194 u32 _rdhi = prepare_store_reg(reg_a1, rdhi); \
1195 arm_multiply_long_add_##add_op(name); \
1196 arm_multiply_long_op(flags, arm_multiply_long_name_##name); \
1197 complete_store_reg(_rdlo, rdlo); \
1198 complete_store_reg(_rdhi, rdhi); \
1199 } \
1200
1201 #define arm_psr_read_cpsr() \
1202 u32 _rd = prepare_store_reg(reg_a0, rd); \
1203 generate_load_reg(_rd, REG_CPSR); \
1204 ARM_BIC_REG_IMM(0, _rd, _rd, 0xF0, arm_imm_lsl_to_rot(24)); \
1205 ARM_AND_REG_IMM(0, reg_flags, reg_flags, 0xF0, arm_imm_lsl_to_rot(24)); \
1206 ARM_ORR_REG_REG(0, _rd, _rd, reg_flags); \
1207 complete_store_reg(_rd, rd) \
1208
1209 #define arm_psr_read_spsr() \
1210 generate_function_call(execute_read_spsr) \
1211 generate_store_reg(reg_a0, rd) \
1212
1213 #define arm_psr_read(op_type, psr_reg) \
1214 arm_psr_read_##psr_reg() \
1215
1216 /* This function's okay because it's called from an ASM function that can
1217 * wrap it correctly.
1218 */
1219
execute_store_cpsr_body(u32 _cpsr,u32 store_mask,u32 address)1220 u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address)
1221 {
1222 reg[REG_CPSR] = _cpsr;
1223 if(store_mask & 0xFF)
1224 {
1225 set_cpu_mode(cpu_modes[_cpsr & 0x1F]);
1226 if((io_registers[REG_IE] & io_registers[REG_IF]) &&
1227 io_registers[REG_IME] && ((_cpsr & 0x80) == 0))
1228 {
1229 reg_mode[MODE_IRQ][6] = address + 4;
1230 spsr[MODE_IRQ] = _cpsr;
1231 reg[REG_CPSR] = 0xD2;
1232 set_cpu_mode(MODE_IRQ);
1233 return 0x00000018;
1234 }
1235 }
1236
1237 return 0;
1238 }
1239
1240 #define arm_psr_load_new_reg() \
1241 generate_load_reg(reg_a0, rm) \
1242
1243 #define arm_psr_load_new_imm() \
1244 generate_load_imm(reg_a0, imm, imm_ror) \
1245
1246 #define arm_psr_store_cpsr() \
1247 arm_load_imm_32bit(reg_a1, psr_masks[psr_field]); \
1248 generate_function_call(execute_store_cpsr); \
1249 write32(pc) \
1250
1251 #define arm_psr_store_spsr() \
1252 generate_function_call(execute_store_spsr) \
1253
1254 #define arm_psr_store(op_type, psr_reg) \
1255 arm_psr_load_new_##op_type(); \
1256 arm_psr_store_##psr_reg() \
1257
1258
1259 #define arm_psr(op_type, transfer_type, psr_reg) \
1260 { \
1261 arm_decode_psr_##op_type(opcode); \
1262 arm_psr_##transfer_type(op_type, psr_reg); \
1263 } \
1264
1265 /* TODO: loads will need the PC passed as well for open address, however can
1266 * eventually be rectified with a hash table on the memory accesses
1267 * (same with the stores)
1268 */
1269
1270 #define arm_access_memory_load(mem_type) \
1271 cycle_count += 2; \
1272 generate_function_call(execute_load_##mem_type); \
1273 write32((pc + 8)); \
1274 generate_store_reg_pc_no_flags(reg_rv, rd) \
1275
1276 #define arm_access_memory_store(mem_type) \
1277 cycle_count++; \
1278 generate_load_reg_pc(reg_a1, rd, 12); \
1279 generate_function_call(execute_store_##mem_type); \
1280 write32((pc + 4)) \
1281
1282 /* Calculate the address into a0 from _rn, _rm */
1283
1284 #define arm_access_memory_adjust_reg_sh_up(ireg) \
1285 ARM_ADD_REG_IMMSHIFT(0, ireg, _rn, _rm, ((opcode >> 5) & 0x03), \
1286 ((opcode >> 7) & 0x1F)) \
1287
1288 #define arm_access_memory_adjust_reg_sh_down(ireg) \
1289 ARM_SUB_REG_IMMSHIFT(0, ireg, _rn, _rm, ((opcode >> 5) & 0x03), \
1290 ((opcode >> 7) & 0x1F)) \
1291
1292 #define arm_access_memory_adjust_reg_up(ireg) \
1293 ARM_ADD_REG_REG(0, ireg, _rn, _rm) \
1294
1295 #define arm_access_memory_adjust_reg_down(ireg) \
1296 ARM_SUB_REG_REG(0, ireg, _rn, _rm) \
1297
1298 #define arm_access_memory_adjust_imm(op, ireg) \
1299 { \
1300 u32 stores[4]; \
1301 u32 rotations[4]; \
1302 u32 store_count = arm_disect_imm_32bit(offset, stores, rotations); \
1303 \
1304 if(store_count > 1) \
1305 { \
1306 ARM_##op##_REG_IMM(0, ireg, _rn, stores[0], rotations[0]); \
1307 ARM_##op##_REG_IMM(0, ireg, ireg, stores[1], rotations[1]); \
1308 } \
1309 else \
1310 { \
1311 ARM_##op##_REG_IMM(0, ireg, _rn, stores[0], rotations[0]); \
1312 } \
1313 } \
1314
1315 #define arm_access_memory_adjust_imm_up(ireg) \
1316 arm_access_memory_adjust_imm(ADD, ireg) \
1317
1318 #define arm_access_memory_adjust_imm_down(ireg) \
1319 arm_access_memory_adjust_imm(SUB, ireg) \
1320
1321
1322 #define arm_access_memory_pre(type, direction) \
1323 arm_access_memory_adjust_##type##_##direction(reg_a0) \
1324
1325 #define arm_access_memory_pre_wb(type, direction) \
1326 arm_access_memory_adjust_##type##_##direction(reg_a0); \
1327 generate_store_reg(reg_a0, rn) \
1328
1329 #define arm_access_memory_post(type, direction) \
1330 u32 _rn_dest = prepare_store_reg(reg_a1, rn); \
1331 if(_rn != reg_a0) \
1332 { \
1333 generate_load_reg(reg_a0, rn); \
1334 } \
1335 arm_access_memory_adjust_##type##_##direction(_rn_dest); \
1336 complete_store_reg(_rn_dest, rn) \
1337
1338
1339 #define arm_data_trans_reg(adjust_op, direction) \
1340 arm_decode_data_trans_reg(); \
1341 u32 _rn = prepare_load_reg_pc(reg_a0, rn, 8); \
1342 u32 _rm = prepare_load_reg(reg_a1, rm); \
1343 arm_access_memory_##adjust_op(reg_sh, direction) \
1344
1345 #define arm_data_trans_imm(adjust_op, direction) \
1346 arm_decode_data_trans_imm(); \
1347 u32 _rn = prepare_load_reg_pc(reg_a0, rn, 8); \
1348 arm_access_memory_##adjust_op(imm, direction) \
1349
1350
1351 #define arm_data_trans_half_reg(adjust_op, direction) \
1352 arm_decode_half_trans_r(); \
1353 u32 _rn = prepare_load_reg_pc(reg_a0, rn, 8); \
1354 u32 _rm = prepare_load_reg(reg_a1, rm); \
1355 arm_access_memory_##adjust_op(reg, direction) \
1356
1357 #define arm_data_trans_half_imm(adjust_op, direction) \
1358 arm_decode_half_trans_of(); \
1359 u32 _rn = prepare_load_reg_pc(reg_a0, rn, 8); \
1360 arm_access_memory_##adjust_op(imm, direction) \
1361
1362
1363 #define arm_access_memory(access_type, direction, adjust_op, mem_type, \
1364 offset_type) \
1365 { \
1366 arm_data_trans_##offset_type(adjust_op, direction); \
1367 arm_access_memory_##access_type(mem_type); \
1368 } \
1369
1370
1371 #define word_bit_count(word) \
1372 (bit_count[word >> 8] + bit_count[word & 0xFF]) \
1373
1374 #define sprint_no(access_type, pre_op, post_op, wb) \
1375
1376 #define sprint_yes(access_type, pre_op, post_op, wb) \
1377 printf("sbit on %s %s %s %s\n", #access_type, #pre_op, #post_op, #wb) \
1378
1379
1380 /* TODO: Make these use cached registers. Implement iwram_stack_optimize. */
1381
1382 #define arm_block_memory_load() \
1383 generate_function_call(execute_load_u32); \
1384 write32((pc + 8)); \
1385 generate_store_reg(reg_rv, i) \
1386
1387 #define arm_block_memory_store() \
1388 generate_load_reg_pc(reg_a1, i, 8); \
1389 generate_function_call(execute_store_u32_safe) \
1390
1391 #define arm_block_memory_final_load() \
1392 arm_block_memory_load() \
1393
1394 #define arm_block_memory_final_store() \
1395 generate_load_reg_pc(reg_a1, i, 12); \
1396 generate_function_call(execute_store_u32); \
1397 write32((pc + 4)) \
1398
1399 #define arm_block_memory_adjust_pc_store() \
1400
1401 #define arm_block_memory_adjust_pc_load() \
1402 if(reg_list & 0x8000) \
1403 { \
1404 generate_mov(reg_a0, reg_rv); \
1405 generate_indirect_branch_arm(); \
1406 } \
1407
1408 #define arm_block_memory_offset_down_a() \
1409 generate_sub_imm(reg_s0, ((word_bit_count(reg_list) * 4) - 4), 0) \
1410
1411 #define arm_block_memory_offset_down_b() \
1412 generate_sub_imm(reg_s0, (word_bit_count(reg_list) * 4), 0) \
1413
1414 #define arm_block_memory_offset_no() \
1415
1416 #define arm_block_memory_offset_up() \
1417 generate_add_imm(reg_s0, 4, 0) \
1418
1419 #define arm_block_memory_writeback_down() \
1420 generate_load_reg(reg_a0, rn); \
1421 generate_sub_imm(reg_a0, (word_bit_count(reg_list) * 4), 0); \
1422 generate_store_reg(reg_a0, rn) \
1423
1424 #define arm_block_memory_writeback_up() \
1425 generate_load_reg(reg_a0, rn); \
1426 generate_add_imm(reg_a0, (word_bit_count(reg_list) * 4), 0); \
1427 generate_store_reg(reg_a0, rn) \
1428
1429 #define arm_block_memory_writeback_no()
1430
1431 /* Only emit writeback if the register is not in the list */
1432
1433 #define arm_block_memory_writeback_load(writeback_type) \
1434 if(!((reg_list >> rn) & 0x01)) \
1435 { \
1436 arm_block_memory_writeback_##writeback_type(); \
1437 } \
1438
1439 #define arm_block_memory_writeback_store(writeback_type) \
1440 arm_block_memory_writeback_##writeback_type() \
1441
1442 #define arm_block_memory(access_type, offset_type, writeback_type, s_bit) \
1443 { \
1444 arm_decode_block_trans(); \
1445 u32 offset = 0; \
1446 u32 i; \
1447 \
1448 generate_load_reg(reg_s0, rn); \
1449 arm_block_memory_offset_##offset_type(); \
1450 arm_block_memory_writeback_##access_type(writeback_type); \
1451 ARM_BIC_REG_IMM(0, reg_s0, reg_s0, 0x03, 0); \
1452 \
1453 for(i = 0; i < 16; i++) \
1454 { \
1455 if((reg_list >> i) & 0x01) \
1456 { \
1457 cycle_count++; \
1458 generate_add_reg_reg_imm(reg_a0, reg_s0, offset, 0); \
1459 if(reg_list & ~((2 << i) - 1)) \
1460 { \
1461 arm_block_memory_##access_type(); \
1462 offset += 4; \
1463 } \
1464 else \
1465 { \
1466 arm_block_memory_final_##access_type(); \
1467 break; \
1468 } \
1469 } \
1470 } \
1471 \
1472 arm_block_memory_adjust_pc_##access_type(); \
1473 } \
1474
1475 #define arm_swap(type) \
1476 { \
1477 arm_decode_swap(); \
1478 cycle_count += 3; \
1479 generate_load_reg(reg_a0, rn); \
1480 generate_function_call(execute_load_##type); \
1481 write32((pc + 8)); \
1482 generate_mov(reg_s0, reg_rv); \
1483 generate_load_reg(reg_a0, rn); \
1484 generate_load_reg(reg_a1, rm); \
1485 generate_function_call(execute_store_##type); \
1486 write32((pc + 4)); \
1487 generate_store_reg(reg_s0, rd); \
1488 } \
1489
1490
1491 #define thumb_generate_op_reg(name, _rd, _rs, _rn) \
1492 u32 __rm = prepare_load_reg(reg_rm, _rn); \
1493 generate_op_##name##_reg_immshift(__rd, __rn, __rm, ARMSHIFT_LSL, 0) \
1494
1495 #define thumb_generate_op_imm(name, _rd, _rs, imm_) \
1496 { \
1497 u32 imm_ror = 0; \
1498 generate_op_##name##_imm(__rd, __rn); \
1499 } \
1500
1501
1502 #define thumb_data_proc(type, name, op_type, _rd, _rs, _rn) \
1503 { \
1504 thumb_decode_##type(); \
1505 u32 __rn = prepare_load_reg(reg_rn, _rs); \
1506 u32 __rd = prepare_store_reg(reg_rd, _rd); \
1507 thumb_generate_op_##op_type(name, _rd, _rs, _rn); \
1508 complete_store_reg(__rd, _rd); \
1509 } \
1510
1511 #define thumb_data_proc_test(type, name, op_type, _rd, _rs) \
1512 { \
1513 thumb_decode_##type(); \
1514 u32 __rn = prepare_load_reg(reg_rn, _rd); \
1515 thumb_generate_op_##op_type(name, 0, _rd, _rs); \
1516 } \
1517
1518 #define thumb_data_proc_unary(type, name, op_type, _rd, _rs) \
1519 { \
1520 thumb_decode_##type(); \
1521 u32 __rd = prepare_store_reg(reg_rd, _rd); \
1522 thumb_generate_op_##op_type(name, _rd, 0, _rs); \
1523 complete_store_reg(__rd, _rd); \
1524 } \
1525
1526
1527 #define complete_store_reg_pc_thumb() \
1528 if(rd == 15) \
1529 { \
1530 generate_indirect_branch_cycle_update(thumb); \
1531 } \
1532 else \
1533 { \
1534 complete_store_reg(_rd, rd); \
1535 } \
1536
1537 #define thumb_data_proc_hi(name) \
1538 { \
1539 thumb_decode_hireg_op(); \
1540 u32 _rd = prepare_load_reg_pc(reg_rd, rd, 4); \
1541 u32 _rs = prepare_load_reg_pc(reg_rn, rs, 4); \
1542 generate_op_##name##_reg_immshift(_rd, _rd, _rs, ARMSHIFT_LSL, 0); \
1543 complete_store_reg_pc_thumb(); \
1544 } \
1545
1546 #define thumb_data_proc_test_hi(name) \
1547 { \
1548 thumb_decode_hireg_op(); \
1549 u32 _rd = prepare_load_reg_pc(reg_rd, rd, 4); \
1550 u32 _rs = prepare_load_reg_pc(reg_rn, rs, 4); \
1551 generate_op_##name##_reg_immshift(0, _rd, _rs, ARMSHIFT_LSL, 0); \
1552 } \
1553
1554 #define thumb_data_proc_mov_hi() \
1555 { \
1556 thumb_decode_hireg_op(); \
1557 u32 _rs = prepare_load_reg_pc(reg_rn, rs, 4); \
1558 u32 _rd = prepare_store_reg(reg_rd, rd); \
1559 ARM_MOV_REG_REG(0, _rd, _rs); \
1560 complete_store_reg_pc_thumb(); \
1561 } \
1562
1563
1564
1565 #define thumb_load_pc(_rd) \
1566 { \
1567 thumb_decode_imm(); \
1568 u32 __rd = prepare_store_reg(reg_rd, _rd); \
1569 generate_load_pc(__rd, (((pc & ~2) + 4) + (imm * 4))); \
1570 complete_store_reg(__rd, _rd); \
1571 } \
1572
1573 #define thumb_load_sp(_rd) \
1574 { \
1575 thumb_decode_imm(); \
1576 u32 __sp = prepare_load_reg(reg_a0, REG_SP); \
1577 u32 __rd = prepare_store_reg(reg_a0, _rd); \
1578 ARM_ADD_REG_IMM(0, __rd, __sp, imm, arm_imm_lsl_to_rot(2)); \
1579 complete_store_reg(__rd, _rd); \
1580 } \
1581
1582 #define thumb_adjust_sp_up() \
1583 ARM_ADD_REG_IMM(0, _sp, _sp, imm, arm_imm_lsl_to_rot(2)) \
1584
1585 #define thumb_adjust_sp_down() \
1586 ARM_SUB_REG_IMM(0, _sp, _sp, imm, arm_imm_lsl_to_rot(2)) \
1587
1588 #define thumb_adjust_sp(direction) \
1589 { \
1590 thumb_decode_add_sp(); \
1591 u32 _sp = prepare_load_reg(reg_a0, REG_SP); \
1592 thumb_adjust_sp_##direction(); \
1593 complete_store_reg(_sp, REG_SP); \
1594 } \
1595
1596 #define generate_op_lsl_reg(_rd, _rm, _rs) \
1597 generate_op_movs_reg_regshift(_rd, 0, _rm, ARMSHIFT_LSL, _rs) \
1598
1599 #define generate_op_lsr_reg(_rd, _rm, _rs) \
1600 generate_op_movs_reg_regshift(_rd, 0, _rm, ARMSHIFT_LSR, _rs) \
1601
1602 #define generate_op_asr_reg(_rd, _rm, _rs) \
1603 generate_op_movs_reg_regshift(_rd, 0, _rm, ARMSHIFT_ASR, _rs) \
1604
1605 #define generate_op_ror_reg(_rd, _rm, _rs) \
1606 generate_op_movs_reg_regshift(_rd, 0, _rm, ARMSHIFT_ROR, _rs) \
1607
1608
1609 #define generate_op_lsl_imm(_rd, _rm) \
1610 generate_op_movs_reg_immshift(_rd, 0, _rm, ARMSHIFT_LSL, imm) \
1611
1612 #define generate_op_lsr_imm(_rd, _rm) \
1613 generate_op_movs_reg_immshift(_rd, 0, _rm, ARMSHIFT_LSR, imm) \
1614
1615 #define generate_op_asr_imm(_rd, _rm) \
1616 generate_op_movs_reg_immshift(_rd, 0, _rm, ARMSHIFT_ASR, imm) \
1617
1618 #define generate_op_ror_imm(_rd, _rm) \
1619 generate_op_movs_reg_immshift(_rd, 0, _rm, ARMSHIFT_ROR, imm) \
1620
1621
1622 #define generate_shift_reg(op_type) \
1623 u32 __rm = prepare_load_reg(reg_rd, rd); \
1624 u32 __rs = prepare_load_reg(reg_rs, rs); \
1625 generate_op_##op_type##_reg(__rd, __rm, __rs) \
1626
1627 #define generate_shift_imm(op_type) \
1628 u32 __rs = prepare_load_reg(reg_rs, rs); \
1629 generate_op_##op_type##_imm(__rd, __rs) \
1630
1631
1632 #define thumb_shift(decode_type, op_type, value_type) \
1633 { \
1634 thumb_decode_##decode_type(); \
1635 u32 __rd = prepare_store_reg(reg_rd, rd); \
1636 generate_shift_##value_type(op_type); \
1637 complete_store_reg(__rd, rd); \
1638 } \
1639
1640 /* Operation types: imm, mem_reg, mem_imm */
1641
1642 #define thumb_access_memory_load(mem_type, _rd) \
1643 cycle_count += 2; \
1644 generate_function_call(execute_load_##mem_type); \
1645 write32((pc + 4)); \
1646 generate_store_reg(reg_rv, _rd) \
1647
1648 #define thumb_access_memory_store(mem_type, _rd) \
1649 cycle_count++; \
1650 generate_load_reg(reg_a1, _rd); \
1651 generate_function_call(execute_store_##mem_type); \
1652 write32((pc + 2)) \
1653
1654 #define thumb_access_memory_generate_address_pc_relative(offset, _rb, _ro) \
1655 generate_load_pc(reg_a0, (offset)) \
1656
1657 #define thumb_access_memory_generate_address_reg_imm(offset, _rb, _ro) \
1658 u32 __rb = prepare_load_reg(reg_a0, _rb); \
1659 ARM_ADD_REG_IMM(0, reg_a0, __rb, offset, 0) \
1660
1661 #define thumb_access_memory_generate_address_reg_imm_sp(offset, _rb, _ro) \
1662 u32 __rb = prepare_load_reg(reg_a0, _rb); \
1663 ARM_ADD_REG_IMM(0, reg_a0, __rb, offset, arm_imm_lsl_to_rot(2)) \
1664
1665 #define thumb_access_memory_generate_address_reg_reg(offset, _rb, _ro) \
1666 u32 __rb = prepare_load_reg(reg_a0, _rb); \
1667 u32 __ro = prepare_load_reg(reg_a1, _ro); \
1668 ARM_ADD_REG_REG(0, reg_a0, __rb, __ro) \
1669
1670 #define thumb_access_memory(access_type, op_type, _rd, _rb, _ro, \
1671 address_type, offset, mem_type) \
1672 { \
1673 thumb_decode_##op_type(); \
1674 thumb_access_memory_generate_address_##address_type(offset, _rb, _ro); \
1675 thumb_access_memory_##access_type(mem_type, _rd); \
1676 } \
1677
1678 /* TODO: Make these use cached registers. Implement iwram_stack_optimize. */
1679
1680 #define thumb_block_address_preadjust_up() \
1681 generate_add_imm(reg_s0, (bit_count[reg_list] * 4), 0) \
1682
1683 #define thumb_block_address_preadjust_down() \
1684 generate_sub_imm(reg_s0, (bit_count[reg_list] * 4), 0) \
1685
1686 #define thumb_block_address_preadjust_push_lr() \
1687 generate_sub_imm(reg_s0, ((bit_count[reg_list] + 1) * 4), 0) \
1688
1689 #define thumb_block_address_preadjust_no() \
1690
1691 #define thumb_block_address_postadjust_no(base_reg) \
1692 generate_store_reg(reg_s0, base_reg) \
1693
1694 #define thumb_block_address_postadjust_up(base_reg) \
1695 generate_add_reg_reg_imm(reg_a0, reg_s0, (bit_count[reg_list] * 4), 0); \
1696 generate_store_reg(reg_a0, base_reg) \
1697
1698 #define thumb_block_address_postadjust_down(base_reg) \
1699 generate_mov(reg_a0, reg_s0); \
1700 generate_sub_imm(reg_a0, (bit_count[reg_list] * 4), 0); \
1701 generate_store_reg(reg_a0, base_reg) \
1702
1703 #define thumb_block_address_postadjust_pop_pc(base_reg) \
1704 generate_add_reg_reg_imm(reg_a0, reg_s0, \
1705 ((bit_count[reg_list] + 1) * 4), 0); \
1706 generate_store_reg(reg_a0, base_reg) \
1707
1708 #define thumb_block_address_postadjust_push_lr(base_reg) \
1709 generate_store_reg(reg_s0, base_reg) \
1710
1711 #define thumb_block_memory_extra_no() \
1712
1713 #define thumb_block_memory_extra_up() \
1714
1715 #define thumb_block_memory_extra_down() \
1716
1717 #define thumb_block_memory_extra_pop_pc() \
1718 generate_add_reg_reg_imm(reg_a0, reg_s0, (bit_count[reg_list] * 4), 0); \
1719 generate_function_call(execute_load_u32); \
1720 write32((pc + 4)); \
1721 generate_mov(reg_a0, reg_rv); \
1722 generate_indirect_branch_cycle_update(thumb) \
1723
1724 #define thumb_block_memory_extra_push_lr(base_reg) \
1725 generate_add_reg_reg_imm(reg_a0, reg_s0, (bit_count[reg_list] * 4), 0); \
1726 generate_load_reg(reg_a1, REG_LR); \
1727 generate_function_call(execute_store_u32_safe) \
1728
1729 #define thumb_block_memory_load() \
1730 generate_function_call(execute_load_u32); \
1731 write32((pc + 4)); \
1732 generate_store_reg(reg_rv, i) \
1733
1734 #define thumb_block_memory_store() \
1735 generate_load_reg(reg_a1, i); \
1736 generate_function_call(execute_store_u32_safe) \
1737
1738 #define thumb_block_memory_final_load() \
1739 thumb_block_memory_load() \
1740
1741 #define thumb_block_memory_final_store() \
1742 generate_load_reg(reg_a1, i); \
1743 generate_function_call(execute_store_u32); \
1744 write32((pc + 2)) \
1745
1746 #define thumb_block_memory_final_no(access_type) \
1747 thumb_block_memory_final_##access_type() \
1748
1749 #define thumb_block_memory_final_up(access_type) \
1750 thumb_block_memory_final_##access_type() \
1751
1752 #define thumb_block_memory_final_down(access_type) \
1753 thumb_block_memory_final_##access_type() \
1754
1755 #define thumb_block_memory_final_push_lr(access_type) \
1756 thumb_block_memory_##access_type() \
1757
1758 #define thumb_block_memory_final_pop_pc(access_type) \
1759 thumb_block_memory_##access_type() \
1760
1761 #define thumb_block_memory(access_type, pre_op, post_op, base_reg) \
1762 { \
1763 thumb_decode_rlist(); \
1764 u32 i; \
1765 u32 offset = 0; \
1766 \
1767 generate_load_reg(reg_s0, base_reg); \
1768 ARM_BIC_REG_IMM(0, reg_s0, reg_s0, 0x03, 0); \
1769 thumb_block_address_preadjust_##pre_op(); \
1770 thumb_block_address_postadjust_##post_op(base_reg); \
1771 \
1772 for(i = 0; i < 8; i++) \
1773 { \
1774 if((reg_list >> i) & 0x01) \
1775 { \
1776 cycle_count++; \
1777 generate_add_reg_reg_imm(reg_a0, reg_s0, offset, 0); \
1778 if(reg_list & ~((2 << i) - 1)) \
1779 { \
1780 thumb_block_memory_##access_type(); \
1781 offset += 4; \
1782 } \
1783 else \
1784 { \
1785 thumb_block_memory_final_##post_op(access_type); \
1786 break; \
1787 } \
1788 } \
1789 } \
1790 \
1791 thumb_block_memory_extra_##post_op(); \
1792 } \
1793
1794 #define thumb_conditional_branch(condition) \
1795 { \
1796 generate_cycle_update(); \
1797 generate_load_flags(); \
1798 generate_branch_filler(condition_opposite_##condition, backpatch_address); \
1799 generate_branch_no_cycle_update( \
1800 block_exits[block_exit_position].branch_source, \
1801 block_exits[block_exit_position].branch_target, thumb); \
1802 generate_branch_patch_conditional(backpatch_address, translation_ptr); \
1803 block_exit_position++; \
1804 } \
1805
1806
1807 #define arm_conditional_block_header() \
1808 generate_cycle_update(); \
1809 generate_load_flags(); \
1810 /* This will choose the opposite condition */ \
1811 condition ^= 0x01; \
1812 generate_branch_filler(condition, backpatch_address) \
1813
1814 #define arm_b() \
1815 generate_branch(arm) \
1816
1817 #define arm_bl() \
1818 generate_update_pc((pc + 4)); \
1819 generate_store_reg(reg_a0, REG_LR); \
1820 generate_branch(arm) \
1821
1822 #define arm_bx() \
1823 arm_decode_branchx(opcode); \
1824 generate_load_reg(reg_a0, rn); \
1825 generate_indirect_branch_dual(); \
1826
1827 #define arm_swi() \
1828 generate_swi_hle_handler((opcode >> 16) & 0xFF, arm); \
1829 generate_function_call(execute_swi_arm); \
1830 write32((pc + 4)); \
1831 generate_branch(arm) \
1832
1833 #define thumb_b() \
1834 generate_branch(thumb) \
1835
1836 #define thumb_bl() \
1837 generate_update_pc(((pc + 2) | 0x01)); \
1838 generate_store_reg(reg_a0, REG_LR); \
1839 generate_branch(thumb) \
1840
1841 #define thumb_blh() \
1842 { \
1843 thumb_decode_branch(); \
1844 generate_update_pc(((pc + 2) | 0x01)); \
1845 generate_load_reg(reg_a1, REG_LR); \
1846 generate_store_reg(reg_a0, REG_LR); \
1847 generate_mov(reg_a0, reg_a1); \
1848 generate_add_imm(reg_a0, (offset * 2), 0); \
1849 generate_indirect_branch_cycle_update(thumb); \
1850 } \
1851
1852 #define thumb_bx() \
1853 { \
1854 thumb_decode_hireg_op(); \
1855 generate_load_reg_pc(reg_a0, rs, 4); \
1856 generate_indirect_branch_cycle_update(dual_thumb); \
1857 } \
1858
1859 #define thumb_swi() \
1860 generate_swi_hle_handler(opcode & 0xFF, thumb); \
1861 generate_function_call(execute_swi_thumb); \
1862 write32((pc + 2)); \
1863 /* We're in ARM mode now */ \
1864 generate_branch(arm) \
1865
1866 u8 swi_hle_handle[256] =
1867 {
1868 0x0, // SWI 0: SoftReset
1869 0x0, // SWI 1: RegisterRAMReset
1870 0x0, // SWI 2: Halt
1871 0x0, // SWI 3: Stop/Sleep
1872 0x0, // SWI 4: IntrWait
1873 0x0, // SWI 5: VBlankIntrWait
1874 0x1, // SWI 6: Div
1875 0x0, // SWI 7: DivArm
1876 0x0, // SWI 8: Sqrt
1877 0x0, // SWI 9: ArcTan
1878 0x0, // SWI A: ArcTan2
1879 0x0, // SWI B: CpuSet
1880 0x0, // SWI C: CpuFastSet
1881 0x0, // SWI D: GetBIOSCheckSum
1882 0x0, // SWI E: BgAffineSet
1883 0x0, // SWI F: ObjAffineSet
1884 0x0, // SWI 10: BitUnpack
1885 0x0, // SWI 11: LZ77UnCompWram
1886 0x0, // SWI 12: LZ77UnCompVram
1887 0x0, // SWI 13: HuffUnComp
1888 0x0, // SWI 14: RLUnCompWram
1889 0x0, // SWI 15: RLUnCompVram
1890 0x0, // SWI 16: Diff8bitUnFilterWram
1891 0x0, // SWI 17: Diff8bitUnFilterVram
1892 0x0, // SWI 18: Diff16bitUnFilter
1893 0x0, // SWI 19: SoundBias
1894 0x0, // SWI 1A: SoundDriverInit
1895 0x0, // SWI 1B: SoundDriverMode
1896 0x0, // SWI 1C: SoundDriverMain
1897 0x0, // SWI 1D: SoundDriverVSync
1898 0x0, // SWI 1E: SoundChannelClear
1899 0x0, // SWI 1F: MidiKey2Freq
1900 0x0, // SWI 20: SoundWhatever0
1901 0x0, // SWI 21: SoundWhatever1
1902 0x0, // SWI 22: SoundWhatever2
1903 0x0, // SWI 23: SoundWhatever3
1904 0x0, // SWI 24: SoundWhatever4
1905 0x0, // SWI 25: MultiBoot
1906 0x0, // SWI 26: HardReset
1907 0x0, // SWI 27: CustomHalt
1908 0x0, // SWI 28: SoundDriverVSyncOff
1909 0x0, // SWI 29: SoundDriverVSyncOn
1910 0x0 // SWI 2A: SoundGetJumpList
1911 };
1912
1913 void execute_swi_hle_div_arm(void);
1914 void execute_swi_hle_div_thumb(void);
1915
execute_swi_hle_div_c(void)1916 void execute_swi_hle_div_c(void)
1917 {
1918 /* real BIOS supposedly locks up, but game can recover on interrupt */
1919 if (reg[1] == 0)
1920 return;
1921 s32 result = (s32)reg[0] / (s32)reg[1];
1922 reg[1] = (s32)reg[0] % (s32)reg[1];
1923 reg[0] = result;
1924
1925 reg[3] = (result ^ (result >> 31)) - (result >> 31);
1926 }
1927
1928 #define generate_swi_hle_handler(_swi_number, mode) \
1929 { \
1930 u32 swi_number = _swi_number; \
1931 if(swi_hle_handle[swi_number]) \
1932 { \
1933 /* Div */ \
1934 if(swi_number == 0x06) \
1935 { \
1936 generate_function_call(execute_swi_hle_div_##mode); \
1937 } \
1938 break; \
1939 } \
1940 } \
1941
1942 #define generate_translation_gate(type) \
1943 generate_update_pc(pc); \
1944 generate_indirect_branch_no_cycle_update(type) \
1945
1946 #endif
1947