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