drc: fix eabi alignment
[gpsp.git] / arm / arm_stub.S
1 .align 2
2
3 .global arm_update_gba_arm
4 .global arm_update_gba_thumb
5 .global arm_update_gba_idle_arm
6 .global arm_update_gba_idle_thumb
7
8 .global arm_indirect_branch_arm
9 .global arm_indirect_branch_thumb
10 .global arm_indirect_branch_dual_arm
11 .global arm_indirect_branch_dual_thumb
12
13 .global execute_arm_translate
14
15 .global execute_store_u8
16 .global execute_store_u16
17 .global execute_store_u32
18 .global execute_store_u32_safe
19
20 .global execute_load_u8
21 .global execute_load_s8
22 .global execute_load_u16
23 .global execute_load_s16
24 .global execute_load_u32
25
26 .global execute_store_cpsr
27 .global execute_read_spsr
28 .global execute_store_spsr
29 .global execute_spsr_restore
30
31 .global execute_swi_arm
32 .global execute_swi_thumb
33
34 .global execute_patch_bios_read
35 .global execute_patch_bios_protect
36
37 .global execute_bios_ptr_protected
38 .global execute_bios_rom_ptr
39
40
41 .global step_debug_arm
42
43 .global invalidate_icache_region
44 .global invalidate_cache_region
45
46 .global memory_map_read
47 .global memory_map_write
48 .global reg
49
50 #define REG_BASE_OFFSET   1024
51
52 #define REG_R0            (REG_BASE_OFFSET + (0 * 4))
53 #define REG_R1            (REG_BASE_OFFSET + (1 * 4))
54 #define REG_R2            (REG_BASE_OFFSET + (2 * 4))
55 #define REG_R3            (REG_BASE_OFFSET + (3 * 4))
56 #define REG_R4            (REG_BASE_OFFSET + (4 * 4))
57 #define REG_R5            (REG_BASE_OFFSET + (5 * 4))
58 #define REG_R6            (REG_BASE_OFFSET + (6 * 4))
59 #define REG_R7            (REG_BASE_OFFSET + (7 * 4))
60 #define REG_R8            (REG_BASE_OFFSET + (8 * 4))
61 #define REG_R9            (REG_BASE_OFFSET + (9 * 4))
62 #define REG_R10           (REG_BASE_OFFSET + (10 * 4))
63 #define REG_R11           (REG_BASE_OFFSET + (11 * 4))
64 #define REG_R12           (REG_BASE_OFFSET + (12 * 4))
65 #define REG_R13           (REG_BASE_OFFSET + (13 * 4))
66 #define REG_R14           (REG_BASE_OFFSET + (14 * 4))
67 #define REG_SP            (REG_BASE_OFFSET + (13 * 4))
68 #define REG_LR            (REG_BASE_OFFSET + (14 * 4))
69 #define REG_PC            (REG_BASE_OFFSET + (15 * 4))
70
71 #define REG_N_FLAG        (REG_BASE_OFFSET + (16 * 4))
72 #define REG_Z_FLAG        (REG_BASE_OFFSET + (17 * 4))
73 #define REG_C_FLAG        (REG_BASE_OFFSET + (18 * 4))
74 #define REG_V_FLAG        (REG_BASE_OFFSET + (19 * 4))
75 #define REG_CPSR          (REG_BASE_OFFSET + (20 * 4))
76
77 #define REG_SAVE          (REG_BASE_OFFSET + (21 * 4))
78 #define REG_SAVE2         (REG_BASE_OFFSET + (22 * 4))
79 #define REG_SAVE3         (REG_BASE_OFFSET + (23 * 4))
80
81 #define CPU_MODE          (REG_BASE_OFFSET + (29 * 4))
82 #define CPU_HALT_STATE    (REG_BASE_OFFSET + (30 * 4))
83 #define CHANGED_PC_STATUS (REG_BASE_OFFSET + (31 * 4))
84
85
86 #define reg_a0            r0
87 #define reg_a1            r1
88 #define reg_a2            r2
89
90 #define reg_s0            r9
91 #define reg_base          sp
92 #define reg_flags         r11
93
94 #define reg_cycles        r12
95
96 #define reg_x0            r3
97 #define reg_x1            r4
98 #define reg_x2            r5
99 #define reg_x3            r6
100 #define reg_x4            r7
101 #define reg_x5            r8
102
103
104 #define MODE_SUPERVISOR   3
105
106
107 @ Will load the register set from memory into the appropriate cached registers.
108 @ See arm_emit.h for listing explanation.
109
110 #define load_registers_arm()                                                 ;\
111   ldr reg_x0, [reg_base, #REG_R0]                                            ;\
112   ldr reg_x1, [reg_base, #REG_R1]                                            ;\
113   ldr reg_x2, [reg_base, #REG_R6]                                            ;\
114   ldr reg_x3, [reg_base, #REG_R9]                                            ;\
115   ldr reg_x4, [reg_base, #REG_R12]                                           ;\
116   ldr reg_x5, [reg_base, #REG_R14]                                           ;\
117
118 #define load_registers_thumb()                                               ;\
119   ldr reg_x0, [reg_base, #REG_R0]                                            ;\
120   ldr reg_x1, [reg_base, #REG_R1]                                            ;\
121   ldr reg_x2, [reg_base, #REG_R2]                                            ;\
122   ldr reg_x3, [reg_base, #REG_R3]                                            ;\
123   ldr reg_x4, [reg_base, #REG_R4]                                            ;\
124   ldr reg_x5, [reg_base, #REG_R5]                                            ;\
125
126
127 @ Will store the register set from cached registers back to memory.
128
129 #define store_registers_arm()                                                ;\
130   str reg_x0, [reg_base, #REG_R0]                                            ;\
131   str reg_x1, [reg_base, #REG_R1]                                            ;\
132   str reg_x2, [reg_base, #REG_R6]                                            ;\
133   str reg_x3, [reg_base, #REG_R9]                                            ;\
134   str reg_x4, [reg_base, #REG_R12]                                           ;\
135   str reg_x5, [reg_base, #REG_R14]                                           ;\
136
137 #define store_registers_thumb()                                              ;\
138   str reg_x0, [reg_base, #REG_R0]                                            ;\
139   str reg_x1, [reg_base, #REG_R1]                                            ;\
140   str reg_x2, [reg_base, #REG_R2]                                            ;\
141   str reg_x3, [reg_base, #REG_R3]                                            ;\
142   str reg_x4, [reg_base, #REG_R4]                                            ;\
143   str reg_x5, [reg_base, #REG_R5]                                            ;\
144
145
146 @ Returns an updated persistent cpsr with the cached flags register.
147 @ Uses reg as a temporary register and returns the CPSR here.
148
149 #define collapse_flags_no_update(reg)                                        ;\
150   ldr reg, [reg_base, #REG_CPSR]          /* reg = cpsr                    */;\
151   bic reg, reg, #0xF0000000               /* clear ALU flags in cpsr       */;\
152   and reg_flags, reg_flags, #0xF0000000   /* clear non-ALU flags           */;\
153   orr reg, reg, reg_flags                 /* update cpsr with ALU flags    */;\
154
155 @ Updates cpsr using the above macro.
156
157 #define collapse_flags(reg)                                                  ;\
158   collapse_flags_no_update(reg)                                              ;\
159   str reg, [reg_base, #REG_CPSR]                                             ;\
160
161 @ Loads the saved flags register from the persistent cpsr.
162
163 #define extract_flags()                                                      ;\
164   ldr reg_flags, [reg_base, #REG_CPSR]                                       ;\
165   msr cpsr_f, reg_flags                                                      ;\
166
167
168 #define save_flags()                                                         ;\
169   mrs reg_flags, cpsr                                                        ;\
170
171 #define restore_flags()                                                      ;\
172   msr cpsr_f, reg_flags                                                      ;\
173
174 #ifdef __ARM_EABI__
175   @ must align stack
176   #define call_c_saved_regs r2, r3, r12, lr
177 #else
178   #define call_c_saved_regs r3, r12, lr
179 #endif
180
181 @ Calls a C function - all caller save registers which are important to the
182 @ dynarec and to returning from this function are saved.
183
184 #define call_c_function(function)                                            ;\
185   stmdb sp!, { call_c_saved_regs }                                           ;\
186   bl function                                                                ;\
187   ldmia sp!, { call_c_saved_regs }                                           ;\
188
189
190 @ Update the GBA hardware (video, sound, input, etc)
191
192 @ Input:
193 @ r0: current PC
194
195 #define return_straight()                                                    ;\
196   bx lr                                                                      ;\
197
198 #define return_add()                                                         ;\
199   add pc, lr, #4                                                             ;\
200
201 #define load_pc_straight()                                                   ;\
202   ldr r0, [lr, #-8]                                                          ;\
203
204 #define load_pc_add()                                                        ;\
205   ldr r0, [lr]                                                               ;\
206
207
208 #define arm_update_gba_builder(name, mode, return_op)                        ;\
209                                                                              ;\
210 arm_update_gba_##name:                                                       ;\
211   load_pc_##return_op()                                                      ;\
212   str r0, [reg_base, #REG_PC]             /* write out the PC              */;\
213                                                                              ;\
214   save_flags()                                                               ;\
215   collapse_flags(r0)                      /* update the flags              */;\
216                                                                              ;\
217   store_registers_##mode()                /* save out registers            */;\
218   call_c_function(update_gba)             /* update GBA state              */;\
219                                                                              ;\
220   mvn reg_cycles, r0                      /* load new cycle count          */;\
221                                                                              ;\
222   ldr r0, [reg_base, #CHANGED_PC_STATUS]  /* load PC changed status        */;\
223   cmp r0, #0                              /* see if PC has changed         */;\
224   beq 1f                                  /* if not return                 */;\
225                                                                              ;\
226   ldr r0, [reg_base, #REG_PC]             /* load new PC                   */;\
227   ldr r1, [reg_base, #REG_CPSR]           /* r1 = flags                    */;\
228   tst r1, #0x20                           /* see if Thumb bit is set       */;\
229   bne 2f                                  /* if so load Thumb PC           */;\
230                                                                              ;\
231   load_registers_arm()                    /* load ARM regs                 */;\
232   call_c_function(block_lookup_address_arm)                                  ;\
233   restore_flags()                                                            ;\
234   bx r0                                   /* jump to new ARM block         */;\
235                                                                              ;\
236 1:                                                                           ;\
237   load_registers_##mode()                 /* reload registers              */;\
238   restore_flags()                                                            ;\
239   return_##return_op()                                                       ;\
240                                                                              ;\
241 2:                                                                           ;\
242   load_registers_thumb()                  /* load Thumb regs               */;\
243   call_c_function(block_lookup_address_thumb)                                ;\
244   restore_flags()                                                            ;\
245   bx r0                                   /* jump to new ARM block         */;\
246
247
248 arm_update_gba_builder(arm, arm, straight)
249 arm_update_gba_builder(thumb, thumb, straight)
250
251 arm_update_gba_builder(idle_arm, arm, add)
252 arm_update_gba_builder(idle_thumb, thumb, add)
253
254
255
256 @ These are b stubs for performing indirect branches. They are not
257 @ linked to and don't return, instead they link elsewhere.
258
259 @ Input:
260 @ r0: PC to branch to
261
262 arm_indirect_branch_arm:
263   save_flags()
264   call_c_function(block_lookup_address_arm)
265   restore_flags()
266   bx r0
267
268 arm_indirect_branch_thumb:
269   save_flags()
270   call_c_function(block_lookup_address_thumb)
271   restore_flags()
272   bx r0
273
274 arm_indirect_branch_dual_arm:
275   save_flags()
276   tst r0, #0x01                           @ check lower bit
277   bne 1f                                  @ if set going to Thumb mode
278   call_c_function(block_lookup_address_arm)
279   restore_flags()
280   bx r0                                   @ return
281
282 1:
283   bic r0, r0, #0x01
284   store_registers_arm()                   @ save out ARM registers
285   load_registers_thumb()                  @ load in Thumb registers
286   ldr r1, [reg_base, #REG_CPSR]           @ load cpsr
287   orr r1, r1, #0x20                       @ set Thumb mode
288   str r1, [reg_base, #REG_CPSR]           @ store flags
289   call_c_function(block_lookup_address_thumb)
290   restore_flags()
291   bx r0                                   @ return
292
293 arm_indirect_branch_dual_thumb:
294   save_flags()
295   tst r0, #0x01                           @ check lower bit
296   beq 1f                                  @ if set going to ARM mode
297   bic r0, r0, #0x01
298   call_c_function(block_lookup_address_thumb)
299   restore_flags()
300   bx r0                                   @ return
301
302 1:
303   store_registers_thumb()                 @ save out Thumb registers
304   load_registers_arm()                    @ load in ARM registers
305   ldr r1, [reg_base, #REG_CPSR]           @ load cpsr
306   bic r1, r1, #0x20                       @ clear Thumb mode
307   str r1, [reg_base, #REG_CPSR]           @ store flags
308   call_c_function(block_lookup_address_arm)
309   restore_flags()
310   bx r0                                   @ return
311
312
313 @ Update the cpsr.
314
315 @ Input:
316 @ r0: new cpsr value
317 @ r1: bitmask of which bits in cpsr to update
318 @ r2: current PC
319
320 execute_store_cpsr:
321   save_flags()
322   and reg_flags, r0, r1                   @ reg_flags = new_cpsr & store_mask
323   ldr r0, [reg_base, #REG_CPSR]           @ r0 = cpsr
324   bic r0, r0, r1                          @ r0 = cpsr & ~store_mask
325   orr reg_flags, reg_flags, r0            @ reg_flags = new_cpsr | cpsr
326
327   mov r0, reg_flags                       @ also put new cpsr in r0
328
329   store_registers_arm()                   @ save ARM registers
330   ldr r2, [lr]                            @ r2 = pc
331   call_c_function(execute_store_cpsr_body)
332   load_registers_arm()                    @ restore ARM registers
333
334   cmp r0, #0                              @ check new PC
335   beq 1f                                  @ if it's zero, return
336
337   call_c_function(block_lookup_address_arm)
338
339   restore_flags()
340   bx r0                                   @ return to new ARM address
341
342 1:
343   restore_flags()
344   add pc, lr, #4                          @ return
345
346
347 @ Update the current spsr.
348
349 @ Input:
350 @ r0: new cpsr value
351 @ r1: bitmask of which bits in spsr to update
352
353 execute_store_spsr:
354   ldr r1, 1f                              @ r1 = spsr
355   ldr r2, [reg_base, #CPU_MODE]           @ r2 = CPU_MODE
356   str r0, [r1, r2, lsl #2]                @ spsr[CPU_MODE] = new_spsr
357   bx lr
358
359 1:
360   .word spsr
361
362 @ Read the current spsr.
363
364 @ Output:
365 @ r0: spsr
366
367 execute_read_spsr:
368   ldr r0, 1b                              @ r0 = spsr
369   ldr r1, [reg_base, #CPU_MODE]           @ r1 = CPU_MODE
370   ldr r0, [r0, r1, lsl #2]                @ r0 = spsr[CPU_MODE]
371   bx lr                                   @ return
372
373
374 @ Restore the cpsr from the mode spsr and mode shift.
375
376 @ Input:
377 @ r0: current pc
378
379 execute_spsr_restore:
380   save_flags()
381   ldr r1, 1f                              @ r1 = spsr
382   ldr r2, [reg_base, #CPU_MODE]           @ r2 = cpu_mode
383   ldr r1, [r1, r2, lsl #2]                @ r1 = spsr[cpu_mode] (new cpsr)
384   str r1, [reg_base, #REG_CPSR]           @ update cpsr
385   mov reg_flags, r1                       @ also, update shadow flags
386
387   @ This function call will pass r0 (address) and return it.
388   store_registers_arm()                   @ save ARM registers
389   call_c_function(execute_spsr_restore_body)
390
391   ldr r1, [reg_base, #REG_CPSR]           @ r1 = cpsr
392   tst r1, #0x20                           @ see if Thumb mode is set
393   bne 2f                                  @ if so handle it
394
395   load_registers_arm()                    @ restore ARM registers
396   call_c_function(block_lookup_address_arm)
397   restore_flags()
398   bx r0
399
400   @ This will service execute_spsr_restore and execute_swi
401 1:
402   .word spsr
403
404 2:
405   load_registers_thumb()                  @ load Thumb registers
406   call_c_function(block_lookup_address_thumb)
407   restore_flags()
408   bx r0
409
410
411
412 @ Setup the mode transition work for calling an SWI.
413
414 @ Input:
415 @ r0: current pc
416
417 #define execute_swi_builder(mode)                                            ;\
418                                                                              ;\
419 execute_swi_##mode:                                                          ;\
420   save_flags()                                                               ;\
421   ldr r1, 1f                              /* r1 = reg_mode                 */;\
422   /* reg_mode[MODE_SUPERVISOR][6] = pc                                     */;\
423   ldr r0, [lr]                            /* load PC                       */;\
424   str r0, [r1, #((MODE_SUPERVISOR * (7 * 4)) + (6 * 4))]                     ;\
425   collapse_flags_no_update(r0)            /* r0 = cpsr                     */;\
426   ldr r1, 2f                              /* r1 = spsr                     */;\
427   str r0, [r1, #(MODE_SUPERVISOR * 4)]    /* spsr[MODE_SUPERVISOR] = cpsr  */;\
428   bic r0, r0, #0x3F                       /* clear mode flag in r0         */;\
429   orr r0, r0, #0x13                       /* set to supervisor mode        */;\
430   str r0, [reg_base, #REG_CPSR]           /* update cpsr                   */;\
431                                                                              ;\
432   call_c_function(bios_region_read_allow)                                    ;\
433                                                                              ;\
434   mov r0, #MODE_SUPERVISOR                                                   ;\
435                                                                              ;\
436   store_registers_##mode()                /* store regs for mode           */;\
437   call_c_function(set_cpu_mode)           /* set the CPU mode to svsr      */;\
438   load_registers_arm()                    /* load ARM regs                 */;\
439                                                                              ;\
440   restore_flags()                                                            ;\
441   add pc, lr, #4                          /* return                        */;\
442                                                                              ;\
443 1:                                                                           ;\
444   .word reg_mode                                                             ;\
445                                                                              ;\
446 2:                                                                           ;\
447   .word spsr                                                                 ;\
448                                                                              ;\
449 3:                                                                           ;\
450   .word execute_bios_rom_ptr                                                 ;\
451
452 execute_swi_builder(arm)
453 execute_swi_builder(thumb)
454
455
456 @ Wrapper for calling SWI functions in C (or can implement some in ASM if
457 @ desired)
458
459 #define execute_swi_function_builder(swi_function, mode)                     ;\
460                                                                              ;\
461   .global execute_swi_hle_##swi_function##_##mode                            ;\
462 execute_swi_hle_##swi_function##_##mode:                                     ;\
463   save_flags()                                                               ;\
464   store_registers_##mode()                                                   ;\
465   call_c_function(execute_swi_hle_##swi_function##_c)                        ;\
466   load_registers_##mode()                                                    ;\
467   restore_flags()                                                            ;\
468   bx lr                                                                      ;\
469
470 execute_swi_function_builder(div, arm)
471 execute_swi_function_builder(div, thumb)
472
473
474 @ Start program execution. Normally the mode should be Thumb and the
475 @ PC should be 0x8000000, however if a save state is preloaded this
476 @ will be different.
477
478 @ Input:
479 @ r0: initial value for cycle counter
480
481 @ Uses sp as reg_base; must hold consistently true.
482
483 execute_arm_translate:
484   sub sp, sp, #0x100                      @ allocate room for register data
485
486   mvn reg_cycles, r0                      @ load cycle counter
487
488   mov r0, reg_base                        @ load reg_base into first param
489   call_c_function(move_reg)               @ make reg_base the new reg ptr
490
491   sub sp, sp, #REG_BASE_OFFSET            @ allocate room for ptr table
492   bl load_ptr_read_function_table         @ load read function ptr table
493
494   ldr r0, [reg_base, #REG_PC]             @ r0 = current pc
495   ldr r1, [reg_base, #REG_CPSR]           @ r1 = flags
496   tst r1, #0x20                           @ see if Thumb bit is set
497
498   bne 1f                                  @ if so lookup thumb
499
500   load_registers_arm()                    @ load ARM registers
501   call_c_function(block_lookup_address_arm)
502   extract_flags()                         @ load flags
503   bx r0                                   @ jump to first ARM block
504
505 1:
506   load_registers_thumb()                  @ load Thumb registers
507   call_c_function(block_lookup_address_thumb)
508   extract_flags()                         @ load flags
509   bx r0                                   @ jump to first Thumb block
510
511
512 @ Write out to memory.
513
514 @ Input:
515 @ r0: address
516 @ r1: value
517 @ r2: current pc
518
519 #define execute_store_body(store_type, store_op)                             ;\
520   save_flags()                                                               ;\
521   stmdb sp!, { lr }                       /* save lr                       */;\
522   tst r0, #0xF0000000                     /* make sure address is in range */;\
523   bne ext_store_u##store_type             /* if not do ext store           */;\
524                                                                              ;\
525   ldr r2, 1f                              /* r2 = memory_map_write         */;\
526   mov lr, r0, lsr #15                     /* lr = page index of address    */;\
527   ldr r2, [r2, lr, lsl #2]                /* r2 = memory page              */;\
528                                                                              ;\
529   cmp r2, #0                              /* see if map is ext             */;\
530   beq ext_store_u##store_type             /* if so do ext store            */;\
531                                                                              ;\
532   mov r0, r0, lsl #17                     /* isolate bottom 15 bits in top */;\
533   mov r0, r0, lsr #17                     /* like performing and 0x7FFF    */;\
534   store_op r1, [r2, r0]                   /* store result                  */;\
535
536
537 #define store_align_8()                                                      ;\
538
539 #define store_align_16()                                                     ;\
540   bic r0, r0, #0x01                                                          ;\
541
542 #define store_align_32()                                                     ;\
543   bic r0, r0, #0x03                                                          ;\
544
545
546 #define execute_store_builder(store_type, store_op, load_op)                 ;\
547                                                                              ;\
548 execute_store_u##store_type:                                                 ;\
549   execute_store_body(store_type, store_op)                                   ;\
550   sub r2, r2, #0x8000                     /* Pointer to code status data   */;\
551   load_op r0, [r2, r0]                    /* check code flag               */;\
552                                                                              ;\
553   cmp r0, #0                              /* see if it's not 0             */;\
554   bne 2f                                  /* if so perform smc write       */;\
555   ldmia sp!, { lr }                       /* restore lr                    */;\
556   restore_flags()                                                            ;\
557   add pc, lr, #4                          /* return                        */;\
558                                                                              ;\
559 2:                                                                           ;\
560   ldmia sp!, { lr }                       /* restore lr                    */;\
561   ldr r0, [lr]                            /* load PC                       */;\
562   str r0, [reg_base, #REG_PC]             /* write out PC                  */;\
563   b smc_write                             /* perform smc write             */;\
564 1:                                                                           ;\
565   .word memory_map_write                                                     ;\
566                                                                              ;\
567 ext_store_u##store_type:                                                     ;\
568   ldmia sp!, { lr }                       /* pop lr off of stack           */;\
569   ldr r2, [lr]                            /* load PC                       */;\
570   str r2, [reg_base, #REG_PC]             /* write out PC                  */;\
571   store_align_##store_type()                                                 ;\
572   call_c_function(write_memory##store_type)                                  ;\
573   b write_epilogue                        /* handle additional write stuff */;\
574
575 execute_store_builder(8, strb, ldrb)
576 execute_store_builder(16, strh, ldrh)
577 execute_store_builder(32, str, ldr)
578
579
580 execute_store_u32_safe:
581   execute_store_body(32_safe, str)
582   restore_flags()
583   ldmia sp!, { pc }                       @ return
584
585 1:
586   .word memory_map_write
587
588 ext_store_u32_safe:
589   ldmia sp!, { lr }                       @ Restore lr
590   call_c_function(write_memory32)         @ Perform 32bit store
591   restore_flags()
592   bx lr                                   @ Return
593
594
595 write_epilogue:
596   cmp r0, #0                              @ check if the write rose an alert
597   beq 4f                                  @ if not we can exit
598
599   collapse_flags(r1)                      @ interrupt needs current flags
600
601   cmp r0, #2                              @ see if the alert is due to SMC
602   beq smc_write                           @ if so, goto SMC handler
603
604   ldr r1, [reg_base, #REG_CPSR]           @ r1 = cpsr
605   tst r1, #0x20                           @ see if Thumb bit is set
606   bne 1f                                  @ if so do Thumb update
607
608   store_registers_arm()                   @ save ARM registers
609
610 3:
611   bl update_gba                           @ update GBA until CPU isn't halted
612
613   mvn reg_cycles, r0                      @ load new cycle count
614   ldr r0, [reg_base, #REG_PC]             @ load new PC
615   ldr r1, [reg_base, #REG_CPSR]           @ r1 = flags
616   tst r1, #0x20                           @ see if Thumb bit is set
617   bne 2f
618
619   load_registers_arm()
620   call_c_function(block_lookup_address_arm)
621   restore_flags()
622   bx r0                                   @ jump to new ARM block
623
624 1:
625   store_registers_thumb()                 @ save Thumb registers
626   b 3b
627
628 2:
629   load_registers_thumb()
630   call_c_function(block_lookup_address_thumb)
631   restore_flags()
632   bx r0                                   @ jump to new Thumb block
633
634 4:
635   restore_flags()
636   add pc, lr, #4                          @ return
637
638
639 smc_write:
640   call_c_function(flush_translation_cache_ram)
641
642 lookup_pc:
643   ldr r0, [reg_base, #REG_PC]             @ r0 = new pc
644   ldr r1, [reg_base, #REG_CPSR]           @ r1 = flags
645   tst r1, #0x20                           @ see if Thumb bit is set
646   beq lookup_pc_arm                       @ if not lookup ARM
647
648 lookup_pc_thumb:
649   call_c_function(block_lookup_address_thumb)
650   restore_flags()
651   bx r0                                   @ jump to new Thumb block
652
653 lookup_pc_arm:
654   call_c_function(block_lookup_address_arm)
655   restore_flags()
656   bx r0                                   @ jump to new ARM block
657
658
659 #define sign_extend_u8(reg)
660 #define sign_extend_u16(reg)
661 #define sign_extend_u32(reg)
662
663 #define sign_extend_s8(reg)                                                  ;\
664   mov reg, reg, lsl #24                   /* shift reg into upper 8bits    */;\
665   mov reg, reg, asr #24                   /* shift down, sign extending    */;\
666
667 #define sign_extend_s16(reg)                                                 ;\
668   mov reg, reg, lsl #16                   /* shift reg into upper 16bits   */;\
669   mov reg, reg, asr #16                   /* shift down, sign extending    */;\
670
671 #define execute_load_op_u8(load_op)                                          ;\
672   mov r0, r0, lsl #17                                                        ;\
673   load_op r0, [r2, r0, lsr #17]                                              ;\
674
675 #define execute_load_op_s8(load_op)                                          ;\
676   mov r0, r0, lsl #17                                                        ;\
677   mov r0, r0, lsr #17                                                        ;\
678   load_op r0, [r2, r0]                                                       ;\
679
680 #define execute_load_op_u16(load_op)                                         ;\
681   execute_load_op_s8(load_op)                                                ;\
682
683 #define execute_load_op_s16(load_op)                                         ;\
684   execute_load_op_s8(load_op)                                                ;\
685
686 #define execute_load_op_u16(load_op)                                         ;\
687   execute_load_op_s8(load_op)                                                ;\
688
689 #define execute_load_op_u32(load_op)                                         ;\
690   execute_load_op_u8(load_op)                                                ;\
691
692
693 #define execute_load_builder(load_type, load_function, load_op, mask)        ;\
694                                                                              ;\
695 execute_load_##load_type:                                                    ;\
696   save_flags()                                                               ;\
697   tst r0, mask                            /* make sure address is in range */;\
698   bne ext_load_##load_type                /* if not do ext load            */;\
699                                                                              ;\
700   ldr r2, 1f                              /* r2 = memory_map_read          */;\
701   mov r1, r0, lsr #15                     /* r1 = page index of address    */;\
702   ldr r2, [r2, r1, lsl #2]                /* r2 = memory page              */;\
703                                                                              ;\
704   cmp r2, #0                              /* see if map is ext             */;\
705   beq ext_load_##load_type                /* if so do ext load             */;\
706                                                                              ;\
707   execute_load_op_##load_type(load_op)                                       ;\
708   restore_flags()                                                            ;\
709   add pc, lr, #4                          /* return                        */;\
710                                                                              ;\
711 ext_load_##load_type:                                                        ;\
712   ldr r1, [lr]                            /* r1 = PC                       */;\
713   str r1, [reg_base, #REG_PC]             /* update PC                     */;\
714   call_c_function(read_memory##load_function)                                ;\
715   sign_extend_##load_type(r0)             /* sign extend result            */;\
716   restore_flags()                                                            ;\
717   add pc, lr, #4                          /* return                        */;\
718                                                                              ;\
719 1:                                                                           ;\
720   .word memory_map_read                                                      ;\
721
722
723 execute_load_builder(u8, 8, ldrneb, #0xF0000000)
724 execute_load_builder(s8, 8, ldrnesb, #0xF0000000)
725 execute_load_builder(u16, 16, ldrneh, #0xF0000001)
726 execute_load_builder(s16, 16_signed, ldrnesh, #0xF0000001)
727 execute_load_builder(u32, 32, ldrne, #0xF0000000)
728
729
730 #define execute_ptr_builder(region, ptr, bits)                               ;\
731                                                                              ;\
732 execute_##region##_ptr:                                                      ;\
733   ldr r1, 1f                              /* load region ptr               */;\
734   mov r0, r0, lsl #(32 - bits)            /* isolate bottom bits           */;\
735   mov r0, r0, lsr #(32 - bits)                                               ;\
736   bx lr                                   /* return                        */;\
737                                                                              ;\
738 1:                                                                           ;\
739   .word (ptr)                                                                ;\
740
741
742 execute_bios_ptr_protected:
743   ldr r1, 1f                              @ load bios read ptr
744   and r0, r0, #0x03                       @ only want bottom 2 bits
745   bx lr                                   @ return
746
747 1:
748   .word bios_read_protect
749
750
751 @ address = (address & 0x7FFF) + ((address & 0x38000) * 2) + 0x8000;
752
753 execute_ewram_ptr:
754   ldr r1, 1f                              @ load ewram read ptr
755   mov r2, r0, lsl #17                     @ isolate bottom 15 bits
756   mov r2, r2, lsr #17
757   and r0, r0, #0x38000                    @ isolate top 2 bits
758   add r0, r2, r0, lsl #1                  @ add top 2 bits * 2 to bottom 15
759   bx lr                                   @ return
760
761 1:
762   .word (ewram + 0x8000)
763
764
765 @  u32 gamepak_index = address >> 15;
766 @  u8 *map = memory_map_read[gamepak_index];
767
768 @  if(map == NULL)
769 @    map = load_gamepak_page(gamepak_index & 0x3FF);
770
771 @  value = address##type(map, address & 0x7FFF)
772
773 execute_gamepak_ptr:
774   ldr r1, 1f                              @ load memory_map_read
775   mov r2, r0, lsr #15                     @ isolate top 17 bits
776   ldr r1, [r1, r2, lsl #2]                @ load memory map read ptr
777
778   save_flags()
779   cmp r1, #0                              @ see if map entry is NULL
780   bne 2f                                  @ if not resume
781
782   stmdb sp!, { r0 }                       @ save r0 on stack
783   mov r2, r2, lsl #20                     @ isolate page index
784   mov r0, r2, lsr #20
785   call_c_function(load_gamepak_page)      @ read new page into r0
786
787   mov r1, r0                              @ new map = return
788   ldmia sp!, { r0 }                       @ restore r0
789
790 2:
791   mov r0, r0, lsl #17                     @ isolate bottom 15 bits
792   mov r0, r0, lsr #17
793   restore_flags()
794   bx lr                                   @ return
795
796 1:
797   .word memory_map_read
798
799
800 @ These will store the result in a pointer, then pass that pointer.
801
802 execute_eeprom_ptr:
803   save_flags()
804
805   call_c_function(read_eeprom)            @ load EEPROM result
806   add r1, reg_base, #(REG_SAVE & 0xFF00)
807   add r1, r1, #(REG_SAVE & 0xFF)
808   strh r0, [r1]                           @ write result out
809   mov r0, #0                              @ zero out address
810
811   restore_flags()
812   bx lr                                   @ return
813
814
815 execute_backup_ptr:
816   save_flags()
817
818   mov r0, r0, lsl #16                     @ only want top 16 bits
819   mov r0, r0, lsr #16
820   call_c_function(read_backup)            @ load backup result
821   add r1, reg_base, #(REG_SAVE & 0xFF00)
822   add r1, r1, #(REG_SAVE & 0xFF)
823   strb r0, [r1]                           @ write result out
824   mov r0, #0                              @ zero out address
825
826   restore_flags()
827   bx lr                                   @ return
828
829
830 execute_open_ptr:
831   ldr r1, [reg_base, #REG_CPSR]           @ r1 = cpsr
832   save_flags()
833
834   stmdb sp!, { r0 }                       @ save r0
835
836   ldr r0, [lr, #-4]                       @ r0 = current PC
837
838   tst r1, #0x20                           @ see if Thumb bit is set
839   bne 1f                                  @ if so load Thumb op
840
841   call_c_function(read_memory32)          @ read open address
842
843   add r1, reg_base, #((REG_SAVE + 4) & 0xFF00)
844   add r1, r1, #((REG_SAVE + 4) & 0xFF)
845   add r1, r1, reg_base
846   str r0, [r1]                            @ write out
847
848   ldmia sp!, { r0 }                       @ restore r0
849   and r0, r0, #0x03                       @ isolate bottom 2 bits
850
851   restore_flags()
852   bx lr
853
854 1:
855   call_c_function(read_memory16)          @ read open address
856
857   orr r0, r0, r0, lsl #16                 @ duplicate opcode over halves
858   add r1, reg_base, #((REG_SAVE + 4) & 0xFF00)
859   add r1, r1, #((REG_SAVE + 4) & 0xFF)
860
861   add r1, r1, reg_base
862   str r0, [r1]                            @ write out
863
864   ldmia sp!, { r0 }                       @ restore r0
865   and r0, r0, #0x03                       @ isolate bottom 2 bits
866
867   restore_flags();
868   bx lr
869
870
871 execute_ptr_builder(bios_rom, bios_rom, 14)
872 execute_ptr_builder(iwram, iwram + 0x8000, 15)
873 execute_ptr_builder(vram, vram, 17)
874 execute_ptr_builder(oam_ram, oam_ram, 10)
875 execute_ptr_builder(io_registers, io_registers, 10)
876 execute_ptr_builder(palette_ram, palette_ram, 10)
877
878 ptr_read_function_table:
879   .word execute_bios_ptr_protected        @ 0x00: BIOS
880   .word execute_open_ptr                  @ 0x01: open
881   .word execute_ewram_ptr                 @ 0x02: ewram
882   .word execute_iwram_ptr                 @ 0x03: iwram
883   .word execute_io_registers_ptr          @ 0x04: I/O registers
884   .word execute_palette_ram_ptr           @ 0x05: palette RAM
885   .word execute_vram_ptr                  @ 0x06: vram
886   .word execute_oam_ram_ptr               @ 0x07: oam RAM
887   .word execute_gamepak_ptr               @ 0x08: gamepak
888   .word execute_gamepak_ptr               @ 0x09: gamepak
889   .word execute_gamepak_ptr               @ 0x0A: gamepak
890   .word execute_gamepak_ptr               @ 0x0B: gamepak
891   .word execute_gamepak_ptr               @ 0x0C: gamepak
892   .word execute_eeprom_ptr                @ 0x0D: EEPROM
893   .word execute_backup_ptr                @ 0x0E: backup
894
895 .rept (256 - 15)                          @ 0x0F - 0xFF: open
896   .word execute_open_ptr
897 .endr
898
899
900 @ Setup the read function table.
901 @ Load this onto the the stack; assume we're free to use r3
902
903 load_ptr_read_function_table:
904   mov r0, #256                            @ 256 elements
905   ldr r1, 1f                              @ r0 = ptr_read_function_table
906   mov r2, sp                              @ load here
907
908 2:
909   ldr r3, [r1], #4                        @ read pointer
910   str r3, [r2], #4                        @ write pointer
911
912   subs r0, r0, #1                         @ goto next iteration
913   bne 2b
914
915   bx lr
916
917 1:
918   .word ptr_read_function_table
919
920
921 @ Patch the read function table to allow for BIOS reads.
922
923 execute_patch_bios_read:
924   ldr r0, 1f                              @ r0 = patch function
925   ldr r1, 2f                              @ r1 = reg
926   ldr r1, [r1]
927   str r0, [r1, #-REG_BASE_OFFSET]
928   bx lr
929
930 1:
931   .word execute_bios_rom_ptr
932
933 2:
934   .word reg
935
936
937 @ Patch the read function table to allow for BIOS reads.
938
939 execute_patch_bios_protect:
940   ldr r0, 1f                              @ r0 = patch function
941   ldr r1, 2f                              @ r1 = reg
942   ldr r1, [r1]
943   str r0, [r1, #-REG_BASE_OFFSET]
944   bx lr
945
946 1:
947   .word execute_bios_ptr_protected
948
949 2:
950   .word reg
951
952
953 #define save_reg_scratch(reg)                                                 ;\
954   ldr r2, [reg_base, #(REG_BASE_OFFSET + (reg * 4))]                          ;\
955   str r2, [reg_base, #(REG_BASE_OFFSET + (reg * 4) + 128)]                    ;\
956
957 #define restore_reg_scratch(reg)                                              ;\
958   ldr r2, [reg_base, #(REG_BASE_OFFSET + (reg * 4) + 128)]                    ;\
959   str r2, [reg_base, #(REG_BASE_OFFSET + (reg * 4))]                          ;\
960
961 #define scratch_regs_thumb(type)                                              ;\
962   type##_reg_scratch(0)                                                       ;\
963   type##_reg_scratch(1)                                                       ;\
964   type##_reg_scratch(2)                                                       ;\
965   type##_reg_scratch(3)                                                       ;\
966   type##_reg_scratch(4)                                                       ;\
967   type##_reg_scratch(5)                                                       ;\
968
969 #define scratch_regs_arm(type)                                                ;\
970   type##_reg_scratch(0)                                                       ;\
971   type##_reg_scratch(1)                                                       ;\
972   type##_reg_scratch(6)                                                       ;\
973   type##_reg_scratch(9)                                                       ;\
974   type##_reg_scratch(12)                                                      ;\
975   type##_reg_scratch(14)                                                      ;\
976
977
978 step_debug_arm:
979   save_flags()
980   collapse_flags(r0)
981
982   ldr r0, [reg_base, #REG_CPSR]           @ r1 = cpsr
983   tst r0, #0x20                           @ see if Thumb bit is set
984
985   ldr r0, [lr]                            @ load PC
986   mvn r1, reg_cycles                      @ load cycle counter
987
988   beq 1f                                  @ if not goto ARM mode
989
990   scratch_regs_thumb(save)
991
992   store_registers_thumb()                 @ write back Thumb regs
993   call_c_function(step_debug)             @ call debug step
994   scratch_regs_thumb(restore)
995   restore_flags()
996   add pc, lr, #4                          @ return
997
998 1:
999   scratch_regs_arm(save)
1000   store_registers_arm()                   @ write back ARM regs
1001   call_c_function(step_debug)             @ call debug step
1002   scratch_regs_arm(restore)
1003   restore_flags()
1004   add pc, lr, #4                          @ return, skipping PC
1005
1006
1007 .comm memory_map_read 0x8000
1008 .comm memory_map_write 0x8000
1009
1010
1011