diff options
Diffstat (limited to 'psp')
-rw-r--r-- | psp/mips_emit.h | 156 | ||||
-rw-r--r-- | psp/mips_stub.S | 100 |
2 files changed, 159 insertions, 97 deletions
diff --git a/psp/mips_emit.h b/psp/mips_emit.h index 48ed630..506c440 100644 --- a/psp/mips_emit.h +++ b/psp/mips_emit.h @@ -134,6 +134,12 @@ typedef enum typedef enum { + mips_special2_madd = 0x00, + mips_special2_maddu = 0x01, +} mips_function_special2; + +typedef enum +{ mips_special3_ext = 0x00, mips_special3_ins = 0x04, mips_special3_bshfl = 0x20 @@ -203,6 +209,12 @@ typedef enum mips_special_##function; \ translation_ptr += 4 \ +#define mips_emit_special2(function, rs, rt, rd, shift) \ + *((u32 *)translation_ptr) = (mips_opcode_special2 << 26) | \ + (rs << 21) | (rt << 16) | (rd << 11) | (shift << 6) | \ + mips_special2_##function; \ + translation_ptr += 4 \ + #define mips_emit_special3(function, rs, rt, imm_a, imm_b) \ *((u32 *)translation_ptr) = (mips_opcode_special3 << 26) | \ (rs << 21) | (rt << 16) | (imm_a << 11) | (imm_b << 6) | \ @@ -314,11 +326,19 @@ typedef enum #define mips_emit_divu(rs, rt) \ mips_emit_special(divu, rs, rt, 0, 0) \ -#define mips_emit_madd(rs, rt) \ - mips_emit_special(madd, rs, rt, 0, 0) \ +#ifdef PSP + #define mips_emit_madd(rs, rt) \ + mips_emit_special(madd, rs, rt, 0, 0) \ -#define mips_emit_maddu(rs, rt) \ - mips_emit_special(maddu, rs, rt, 0, 0) \ + #define mips_emit_maddu(rs, rt) \ + mips_emit_special(maddu, rs, rt, 0, 0) +#else + #define mips_emit_madd(rs, rt) \ + mips_emit_special2(madd, rs, rt, 0, 0) \ + + #define mips_emit_maddu(rs, rt) \ + mips_emit_special2(maddu, rs, rt, 0, 0) +#endif #define mips_emit_movn(rd, rs, rt) \ mips_emit_special(movn, rs, rt, rd, 0) \ @@ -411,6 +431,9 @@ typedef enum #define mips_emit_jr(rs) \ mips_emit_special(jr, rs, 0, 0, 0) \ +#define mips_emit_jalr(rs) \ + mips_emit_special(jalr, rs, 0, 31, 0) \ + #define mips_emit_synci(rs, offset) \ mips_emit_regimm(synci, rs, offset) \ @@ -2535,8 +2558,9 @@ u8 swi_hle_handle[256] = #define ReOff_GP_Save (32*4) // GP_SAVE // Saves all regs to their right slot and loads gp -#define emit_save_regs(save_a2) \ - for (unsigned i = 0; i < 15; i++) { \ +#define emit_save_regs(save_a2) { \ + int i; \ + for (i = 0; i < 15; i++) { \ mips_emit_sw(arm_to_mips_reg[i], reg_base, 4 * i); \ } \ if (save_a2) { \ @@ -2544,21 +2568,24 @@ u8 swi_hle_handle[256] = } \ /* Load the gp pointer, used by C code */ \ mips_emit_lw(mips_reg_gp, reg_base, ReOff_GP_Save); \ +} // Restores the registers from their slot -#define emit_restore_regs(restore_a2) \ +#define emit_restore_regs(restore_a2) { \ + int i; \ if (restore_a2) { \ mips_emit_lw(reg_a2, reg_base, ReOff_SaveR2); \ } \ - for (unsigned i = 0; i < 15; i++) { \ + for (i = 0; i < 15; i++) { \ mips_emit_lw(arm_to_mips_reg[i], reg_base, 4 * i); \ } \ +} // Emits a function call for a read or a write (for special stuff like flash) #define emit_mem_call_ds(fnptr, mask) \ mips_emit_sw(mips_reg_ra, reg_base, ReOff_SaveR1); \ emit_save_regs(true); \ - mips_emit_jal(((u32)(fnptr)) >> 2); \ + genccall(fnptr); \ mips_emit_andi(reg_a0, reg_a0, (mask)); \ emit_restore_regs(true); \ mips_emit_lw(mips_reg_ra, reg_base, ReOff_SaveR1); \ @@ -2569,10 +2596,10 @@ u8 swi_hle_handle[256] = mips_emit_nop(); // Pointer table to stubs, indexed by type and region -// Caution! This is not really a ptr table, but contains pre-encoed JALs extern u32 tmemld[11][16]; extern u32 tmemst[ 4][16]; void mips_lookup_pc(); +void smc_write(); cpu_alert_type write_io_register8 (u32 address, u32 value); cpu_alert_type write_io_register16(u32 address, u32 value); cpu_alert_type write_io_register32(u32 address, u32 value); @@ -2624,6 +2651,15 @@ static void emit_mem_access_loadop( }; } +#ifdef PIC + #define genccall(fn) \ + mips_emit_lui(mips_reg_t9, ((u32)fn) >> 16); \ + mips_emit_ori(mips_reg_t9, mips_reg_t9, ((u32)fn)); \ + mips_emit_jalr(mips_reg_t9); +#else + #define genccall(fn) mips_emit_jal(((u32)fn) >> 2); +#endif + // Stub memory map: // 0 .. 63 First patch handler [#0] // 448 .. 511 Last patch handler [#7] @@ -2721,7 +2757,7 @@ static void emit_pmemld_stub( emit_save_regs(aligned); mips_emit_sw(mips_reg_ra, reg_base, ReOff_SaveR3); mips_emit_ext(reg_a0, reg_a0, 15, 10); // a0 = (addr >> 15) & 0x3ff - mips_emit_jal(((u32)&load_gamepak_page) >> 2); + genccall(&load_gamepak_page); mips_emit_sw(reg_temp, reg_base, ReOff_SaveR1); mips_emit_lw(reg_temp, reg_base, ReOff_SaveR1); @@ -2891,6 +2927,21 @@ static void emit_pmemst_stub( *tr_ptr = translation_ptr; } +#ifdef USE_BGR_FORMAT + /* 0BGR to BGR565, for PSP */ + #define palette_convert() \ + mips_emit_sll(reg_temp, reg_a1, 1); \ + mips_emit_andi(reg_temp, reg_temp, 0xFFC0); \ + mips_emit_ins(reg_temp, reg_a1, 0, 5); +#else + /* 0BGR to RGB565 (clobbers a0!) */ + #define palette_convert() \ + mips_emit_ext(reg_temp, reg_a1, 10, 5); \ + mips_emit_ins(reg_temp, reg_a1, 11, 5); \ + mips_emit_ext(reg_a0, reg_a1, 5, 5); \ + mips_emit_ins(reg_temp, reg_a0, 6, 5); +#endif + // Palette is accessed differently and stored in a decoded manner static void emit_palette_hdl( unsigned memop_number, const t_stub_meminfo *meminfo, @@ -2923,17 +2974,13 @@ static void emit_palette_hdl( mips_emit_sh(reg_a1, reg_base, 0x100); } - mips_emit_sll(reg_temp, reg_a1, 1); - mips_emit_andi(reg_temp, reg_temp, 0xFFC0); - mips_emit_ins(reg_temp, reg_a1, 0, 5); + palette_convert(); mips_emit_sh(reg_temp, reg_rv, 0x500); if (size == 2) { // Convert the second half-word also mips_emit_srl(reg_a1, reg_a1, 16); - mips_emit_sll(reg_temp, reg_a1, 1); - mips_emit_andi(reg_temp, reg_temp, 0xFFC0); - mips_emit_ins(reg_temp, reg_a1, 0, 5); + palette_convert(); mips_emit_sh(reg_temp, reg_rv, 0x502); } generate_function_return_swap_delay(); @@ -2980,6 +3027,7 @@ static void emit_ignorestore_stub(unsigned size, u8 **tr_ptr) { // Stubs for regions with EEPROM or flash/SRAM static void emit_saveaccess_stub(u8 **tr_ptr) { + unsigned opt, i, strop; u8 *translation_ptr = *tr_ptr; const u8 opmap[6][2] = { {0, 1}, {1, 2}, {2, 4}, {4, 6}, {6, 10}, {10, 11} }; @@ -2995,9 +3043,9 @@ static void emit_saveaccess_stub(u8 **tr_ptr) { emit_mem_call(&write_eeprom, 0x3FF); // Map loads to the read handler. - for (unsigned opt = 0; opt < 6; opt++) { + for (opt = 0; opt < 6; opt++) { // Unalignment is not relevant here, so map them all to the same handler. - for (unsigned i = opmap[opt][0]; i < opmap[opt][1]; i++) + for (i = opmap[opt][0]; i < opmap[opt][1]; i++) tmemld[i][13] = (u32)translation_ptr; // Emit just a check + patch jump mips_emit_srl(reg_temp, reg_a0, 24); @@ -3007,7 +3055,7 @@ static void emit_saveaccess_stub(u8 **tr_ptr) { mips_emit_b(beq, reg_zero, reg_zero, branch_offset(read_hndlr)); } // This is for stores - for (unsigned strop = 0; strop <= 3; strop++) { + for (strop = 0; strop <= 3; strop++) { tmemst[strop][13] = (u32)translation_ptr; mips_emit_srl(reg_temp, reg_a0, 24); mips_emit_xori(reg_rv, reg_temp, 0x0D); @@ -3017,7 +3065,7 @@ static void emit_saveaccess_stub(u8 **tr_ptr) { } // Flash/SRAM/Backup writes are only 8 byte supported - for (unsigned strop = 0; strop <= 3; strop++) { + for (strop = 0; strop <= 3; strop++) { tmemst[strop][14] = (u32)translation_ptr; mips_emit_srl(reg_temp, reg_a0, 24); mips_emit_xori(reg_rv, reg_temp, 0x0E); @@ -3038,7 +3086,7 @@ static void emit_saveaccess_stub(u8 **tr_ptr) { (u32)&write_io_register8, (u32)&write_io_register16, (u32)&write_io_register32, (u32)&write_io_register32 }; const u32 amsk[] = {0x3FF, 0x3FE, 0x3FC, 0x3FC}; - for (unsigned strop = 0; strop <= 3; strop++) { + for (strop = 0; strop <= 3; strop++) { tmemst[strop][4] = (u32)translation_ptr; mips_emit_srl(reg_temp, reg_a0, 24); mips_emit_xori(reg_temp, reg_temp, 0x04); @@ -3047,7 +3095,7 @@ static void emit_saveaccess_stub(u8 **tr_ptr) { mips_emit_sw(mips_reg_ra, reg_base, ReOff_SaveR3); // Store the return addr emit_save_regs(strop == 3); mips_emit_andi(reg_a0, reg_a0, amsk[strop]); - mips_emit_jal(iowrtbl[strop] >> 2); + genccall(iowrtbl[strop]); if (strop < 3) { mips_emit_sw(reg_a2, reg_base, ReOff_RegPC); // Save PC (delay) @@ -3069,6 +3117,7 @@ static void emit_openload_stub( unsigned memopn, bool signext, unsigned size, unsigned alignment, bool aligned, u8 **tr_ptr ) { + u8 *jmp1, *jmp2; u8 *translation_ptr = *tr_ptr; // This affects regions 1 and 15 @@ -3105,30 +3154,31 @@ static void emit_openload_stub( switch (size) { case 0: - mips_emit_b(beq, reg_zero, reg_rv, 2); // Depends on CPU mode mips_emit_andi(reg_a0, reg_a0, 0x3); // ARM: Isolate two LSB - mips_emit_andi(reg_a0, reg_a0, 0x1); // Thb: Isolate one LSB - mips_emit_jal(((u32)&read_memory8) >> 2); + mips_emit_andi(reg_temp, reg_a0, 0x1); // Thb: Isolate one LSB + mips_emit_movn(reg_a0, reg_temp, reg_rv); // Pick thumb or ARM + genccall(&read_memory8); mips_emit_addu(reg_a0, reg_a0, reg_a1); // Add low bits to addr (delay) break; case 1: - mips_emit_b(beq, reg_zero, reg_rv, 2); mips_emit_andi(reg_a0, reg_a0, 0x2); // ARM: Isolate bit 1 - mips_emit_andi(reg_a0, reg_a0, 0x0); // Thb: Ignore low bits at all - mips_emit_jal(((u32)&read_memory16) >> 2); + mips_emit_movn(reg_a0, reg_zero, reg_rv); // Thumb: ignore all low bits + genccall(&read_memory16); mips_emit_addu(reg_a0, reg_a0, reg_a1); // Add low bits to addr (delay) break; default: - mips_emit_b(beq, reg_zero, reg_rv, 5); + mips_emit_b_filler(beq, reg_zero, reg_rv, jmp1); mips_emit_addu(reg_a0, reg_zero, reg_a1); // Move PC to arg0 - mips_emit_jal(((u32)&read_memory16) >> 2); + genccall(&read_memory16); mips_emit_nop(); - mips_emit_b(beq, reg_zero, reg_zero, 3); + mips_emit_b_filler(beq, reg_zero, reg_zero, jmp2); mips_emit_ins(reg_rv, reg_rv, 16, 16); // res = res | (res << 16) [delay] - - mips_emit_jal(((u32)&read_memory32) >> 2); + + generate_branch_patch_conditional(jmp1, translation_ptr); + genccall(&read_memory32); mips_emit_nop(); + generate_branch_patch_conditional(jmp2, translation_ptr); break; }; @@ -3194,9 +3244,14 @@ static void emit_phand( mips_emit_rotr(reg_temp, reg_temp, 6); // Swap opcode and immediate mips_emit_sw(reg_temp, mips_reg_ra, -8); // Patch instruction! + #ifdef PSP mips_emit_cache(0x1A, mips_reg_ra, -8); mips_emit_jr(reg_rv); // Jump directly to target for speed mips_emit_cache(0x08, mips_reg_ra, -8); + #else + mips_emit_jr(reg_rv); + mips_emit_synci(mips_reg_ra, -8); + #endif // Round up handlers to 16 instructions for easy addressing :) while (translation_ptr - *tr_ptr < 64) { @@ -3212,6 +3267,7 @@ static void emit_phand( // - mem stubs: There's stubs for load & store, and every memory region // and possible operand size and misaligment (+sign extensions) void init_emitter() { + int i; // Initialize memory to a debuggable state memset(stub_arena, 0, sizeof(stub_arena)); // nop @@ -3234,25 +3290,8 @@ void init_emitter() { emit_phand(&translation_ptr, 2, 13 * 16, false); // st u32 emit_phand(&translation_ptr, 2, 14 * 16, false); // st aligned 32 - // Generate SMC write handler, with the lookup machinery - // Call out the flushing routine (save PC) - emit_save_regs(false); - mips_emit_jal(((u32)&flush_translation_cache_ram) >> 2); - mips_emit_sw(reg_a2, reg_base, ReOff_RegPC); // Delay slot - - mips_emit_lw(reg_rv, reg_base, ReOff_CPSR); // Read CPSR - mips_emit_andi(reg_rv, reg_rv, 0x20); // Check T bit - mips_emit_b(beq, reg_rv, reg_zero, 3); // Skip to ARM mode - mips_emit_lw(reg_a0, reg_base, ReOff_RegPC); // arg0=pc - // Lookup thumb PC and execute - mips_emit_jal(((u32)&block_lookup_address_thumb) >> 2); - mips_emit_addiu(mips_reg_ra, mips_reg_ra, 8); // Skip 2 insts on return! - // Lookup arm PC and execute - mips_emit_jal(((u32)&block_lookup_address_arm) >> 2); - mips_emit_nop(); - // Epiloge (restore and jump) - emit_restore_regs(false); - mips_emit_jr(reg_rv); // Go execute the code + // This is just a trampoline (for the SMC branches) + mips_emit_j(((u32)&smc_write) >> 2); mips_emit_nop(); // Generate the openload handlers (for accesses to unmapped mem) @@ -3269,7 +3308,7 @@ void init_emitter() { emit_openload_stub(10,false, 2, 0, true, &translation_ptr); // ld aligned 32 // Here we emit the ignore store area, just checks and does nothing - for (unsigned i = 0; i < 4; i++) + for (i = 0; i < 4; i++) emit_ignorestore_stub(i, &translation_ptr); // Here go the save game handlers @@ -3295,7 +3334,7 @@ void init_emitter() { // 15 Open load / Ignore store }; - for (unsigned i = 0; i < sizeof(ldinfo)/sizeof(ldinfo[0]); i++) { + for (i = 0; i < sizeof(ldinfo)/sizeof(ldinfo[0]); i++) { ldhldr_t handler = (ldhldr_t)ldinfo[i].emitter; /* region info signext sz al isaligned */ handler(0, &ldinfo[i], false, 0, 0, false, &translation_ptr); // ld u8 @@ -3325,7 +3364,7 @@ void init_emitter() { // Store only for "regular"-ish mem regions // - for (unsigned i = 0; i < sizeof(stinfo)/sizeof(stinfo[0]); i++) { + for (i = 0; i < sizeof(stinfo)/sizeof(stinfo[0]); i++) { sthldr_t handler = (sthldr_t)stinfo[i].emitter; handler(0, &stinfo[i], 0, false, &translation_ptr); // st u8 handler(1, &stinfo[i], 1, false, &translation_ptr); // st u16 @@ -3334,6 +3373,11 @@ void init_emitter() { } } +u32 execute_arm_translate_internal(u32 cycles, void *regptr); +u32 function_cc execute_arm_translate(u32 cycles) { + return execute_arm_translate_internal(cycles, ®[0]); +} + #endif diff --git a/psp/mips_stub.S b/psp/mips_stub.S index a427e89..2d40bf8 100644 --- a/psp/mips_stub.S +++ b/psp/mips_stub.S @@ -33,13 +33,14 @@ .global execute_lsr_flags_reg .global execute_asr_flags_reg .global execute_ror_flags_reg -.global execute_arm_translate +.global execute_arm_translate_internal .global icache_region_sync .global reg_check .global palette_ram .global palette_ram_converted .global init_emitter .global mips_lookup_pc +.global smc_write .global write_io_epilogue .global memory_map_read @@ -120,6 +121,7 @@ .equ REGMODE_BASE, (0x900 + 24) .equ SUPERVISOR_SPSR, (3 * 4 + SPSR_BASE) .equ SUPERVISOR_LR, ((3 * (7 * 4)) + (6 * 4) + REGMODE_BASE) +.equ FNPTRS_BASE, (0x900 + 220 + 960) .set noat .set noreorder @@ -196,6 +198,22 @@ lw $30, REG_R14($16) .endm +# PIC ABI mandates to jump to target via $t9 + +#ifdef PIC +.macro cfncall target, targetid + lw $t9, (FNPTRS_BASE + \targetid * 4)($16) + jalr $t9 + nop +.endm +#else +.macro cfncall target, targetid + jal \target + nop +.endm +#endif + + # Process a hardware event. Since an interrupt might be # raised we have to check if the PC has changed. @@ -213,8 +231,8 @@ mips_update_gba: sw $ra, REG_SAVE2($16) # save return addr collapse_flags # update cpsr save_registers # save registers - jal update_gba # process the next event sw $0, CHANGED_PC_STATUS($16) + cfncall update_gba, 0 # process the next event lw $1, COMPLETED_FRAME($16) # Check whether we completed a frame bne $1, $0, return_to_main # Return to main thread now @@ -257,26 +275,24 @@ return_to_main: mips_indirect_branch_arm: save_registers - jal block_lookup_address_arm # $2 = MIPS address to jump to - nop + cfncall block_lookup_address_arm, 1 restore_registers - jr $2 # jump to it + jr $2 # $2 = value returned nop mips_indirect_branch_thumb: save_registers - jal block_lookup_address_thumb # $2 = MIPS address to jump to - nop + cfncall block_lookup_address_thumb, 2 restore_registers - jr $2 # jump to it + jr $2 # $2 = value returned nop mips_indirect_branch_dual: save_registers - jal block_lookup_address_dual # $2 = MIPS address to jump to + cfncall block_lookup_address_dual, 3 nop restore_registers - jr $2 # jump to it + jr $2 # $2 = value returned nop @@ -293,8 +309,7 @@ write_io_epilogue: alert_loop: - jal update_gba # process the next event - nop + cfncall update_gba, 0 # process the next event lw $1, COMPLETED_FRAME($16) # Check whether we completed a frame bne $1, $0, return_to_main # Return to main thread now @@ -321,15 +336,14 @@ no_alert: nop smc_dma: - jal flush_translation_cache_ram # flush translation cache - nop + cfncall flush_translation_cache_ram, 4 j lookup_pc nop smc_write: save_registers - jal flush_translation_cache_ram # flush translation cache - sw $6, REG_PC($16) # save PC (delay slot) + sw $6, REG_PC($16) # save PC + cfncall flush_translation_cache_ram, 4 mips_lookup_pc: lookup_pc: @@ -339,17 +353,17 @@ lookup_pc: nop lookup_pc_thumb: - jal block_lookup_address_thumb # get Thumb address - lw $4, REG_PC($16) # load PC as arg 0 (delay slot) + lw $4, REG_PC($16) # load PC as arg 0 + cfncall block_lookup_address_thumb, 2 # get Thumb address restore_registers - jr $2 # jump to result + jr $2 # jump to result nop lookup_pc_arm: - jal block_lookup_address_arm # get ARM address - lw $4, REG_PC($16) # load PC as arg 0 (delay slot) + lw $4, REG_PC($16) # load PC as arg 0 + cfncall block_lookup_address_arm, 1 # get ARM address restore_registers - jr $2 # jump to result + jr $2 # jump to result nop # Return the current cpsr @@ -381,8 +395,8 @@ execute_swi: ori $2, 0x13 # set mode to supervisor sw $2, REG_CPSR($16) # write back CPSR save_registers - jal set_cpu_mode # set the CPU mode to supervisor - li $4, 3 # 3 is supervisor mode (delay slot) + li $4, 3 # 3 is supervisor mode + cfncall set_cpu_mode, 5 # set the CPU mode to supervisor restore_registers lw $ra, ($sp) # pop $ra jr $ra # return @@ -404,8 +418,7 @@ execute_spsr_restore: addiu $sp, $sp, -4 sw $ra, ($sp) save_registers - jal execute_spsr_restore_body # do the dirty work in this C function - nop + cfncall execute_spsr_restore_body, 6 # do the dirty work in this C function restore_registers addu $4, $2, $0 # move return value to $4 lw $ra, ($sp) @@ -429,8 +442,8 @@ execute_store_cpsr: extract_flags_body # extract flags from $1 sw $ra, REG_SAVE3($16) save_registers - jal execute_store_cpsr_body # do the dirty work in this C function - addu $4, $1, $0 # load the new CPSR (delay slot) + addu $4, $1, $0 # load the new CPSR + cfncall execute_store_cpsr_body, 7 # do the dirty work in this C function bne $2, $0, changed_pc_cpsr # this could have changed the pc nop @@ -442,10 +455,10 @@ execute_store_cpsr: nop changed_pc_cpsr: - jal block_lookup_address_arm # GBA address is in $4 - addu $4, $2, $0 # load new address in $4 (delay slot) - restore_registers # restore registers - jr $2 # jump to the new address + addu $4, $2, $0 # load new address in $4 + cfncall block_lookup_address_arm, 1 # GBA address is in $4 + restore_registers # restore registers + jr $2 # jump to the new address nop @@ -549,8 +562,9 @@ ror_zero_shift: rotrv $4, $4, $5 # return (value ror shift) delay # $4: cycle counter argument +# $5: pointer to reg -execute_arm_translate: +execute_arm_translate_internal: add $sp, $sp, -48 # Store the main thread context sw $s0, 0($sp) sw $s1, 4($sp) @@ -563,9 +577,7 @@ execute_arm_translate: sw $fp, 32($sp) sw $ra, 36($sp) - lui $16, %hi(reg) # load reg address into base reg - addiu $16, %lo(reg) - + move $16, $5 sw $28, GP_SAVE($16) addu $17, $4, $0 # load cycle counter register @@ -582,15 +594,13 @@ execute_arm_translate: bne $1, $0, 1f lw $4, REG_PC($16) # load PC into $4 (delay) - jal block_lookup_address_arm # lookup initial jump address - nop + cfncall block_lookup_address_arm, 1 restore_registers # load initial register values jr $2 # jump to return nop 1: - jal block_lookup_address_thumb # lookup initial jump address - nop + cfncall block_lookup_address_thumb, 2 restore_registers # load initial register values jr $2 # jump to return nop @@ -629,5 +639,13 @@ tmemld: .space 704 tmemst: .space 256 - +fnptrs: + .long update_gba # 0 + .long block_lookup_address_arm # 1 + .long block_lookup_address_thumb # 2 + .long block_lookup_address_dual # 3 + .long flush_translation_cache_ram # 4 + .long set_cpu_mode # 5 + .long execute_spsr_restore_body # 6 + .long execute_store_cpsr_body # 7 |