diff options
author | neonloop | 2021-07-03 19:54:16 +0000 |
---|---|---|
committer | neonloop | 2021-07-03 19:54:16 +0000 |
commit | 2815c248d76932787fb58d5bbaa0f26be7bcb2be (patch) | |
tree | eff2b1e2c458fcd0b5f96902382df944048d36b7 | |
parent | 8dec6231614ba3f47d874d551ab83f4c5acb07cb (diff) | |
parent | 3d874ec5e3d5675ae9513264d857a3c6c9d2417c (diff) | |
download | picogpsp-2815c248d76932787fb58d5bbaa0f26be7bcb2be.tar.gz picogpsp-2815c248d76932787fb58d5bbaa0f26be7bcb2be.tar.bz2 picogpsp-2815c248d76932787fb58d5bbaa0f26be7bcb2be.zip |
Merge remote-tracking branch 'libretro/master' into pico-fe
-rw-r--r-- | .gitlab-ci.yml | 32 | ||||
-rw-r--r-- | Makefile | 52 | ||||
-rw-r--r-- | Makefile.common | 4 | ||||
-rw-r--r-- | arm/arm_emit.h | 17 | ||||
-rw-r--r-- | arm/arm_stub.S | 42 | ||||
-rw-r--r-- | cheats.c | 544 | ||||
-rw-r--r-- | cheats.h | 35 | ||||
-rw-r--r-- | common.h | 16 | ||||
-rw-r--r-- | cpu.c | 4368 | ||||
-rw-r--r-- | cpu_threaded.c | 415 | ||||
-rw-r--r-- | gba_memory.c | 465 | ||||
-rw-r--r-- | gba_memory.h | 16 | ||||
-rw-r--r-- | input.c | 76 | ||||
-rw-r--r-- | input.h | 17 | ||||
-rw-r--r-- | libretro.c | 142 | ||||
-rw-r--r-- | libretro.h | 367 | ||||
-rw-r--r-- | libretro_core_options.h | 126 | ||||
-rw-r--r-- | main.c | 26 | ||||
-rw-r--r-- | psp/mips_emit.h | 281 | ||||
-rw-r--r-- | psp/mips_stub.S | 138 | ||||
-rw-r--r-- | sound.c | 10 | ||||
-rw-r--r-- | video.c | 267 | ||||
-rw-r--r-- | x86/x86_emit.h | 12 |
23 files changed, 3718 insertions, 3750 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e3550f2..62b38e9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -63,6 +63,18 @@ include: - project: 'libretro-infrastructure/ci-templates'
file: '/ctr-static.yml'
+ # Nintendo GameCube
+ - project: 'libretro-infrastructure/ci-templates'
+ file: '/ngc-static.yml'
+
+ # Nintendo Wii
+ - project: 'libretro-infrastructure/ci-templates'
+ file: '/wii-static.yml'
+
+ # Nintendo WiiU
+ - project: 'libretro-infrastructure/ci-templates'
+ file: '/wiiu-static.yml'
+
# Nintendo Switch
- project: 'libretro-infrastructure/ci-templates'
file: '/libnx-static.yml'
@@ -174,6 +186,24 @@ libretro-build-ctr: - .libretro-ctr-static-retroarch-master
- .core-defs
+# Nintendo GameCube
+libretro-build-ngc:
+ extends:
+ - .libretro-ngc-static-retroarch-master
+ - .core-defs
+
+# Nintendo Wii
+libretro-build-wii:
+ extends:
+ - .libretro-wii-static-retroarch-master
+ - .core-defs
+
+# Nintendo WiiU
+libretro-build-wiiu:
+ extends:
+ - .libretro-wiiu-static-retroarch-master
+ - .core-defs
+
# OpenDingux
libretro-build-dingux-mips32:
extends:
@@ -185,5 +215,3 @@ libretro-build-dingux-odbeta-mips32: extends:
- .libretro-dingux-odbeta-mips32-make-default
- .core-defs
- variables:
- platform: gcw0-odbeta
@@ -1,5 +1,4 @@ DEBUG=0 -HAVE_GRIFFIN=0 FRONTEND_SUPPORTS_RGB565=1 FORCE_32BIT_ARCH=0 HAVE_MMAP=0 @@ -74,7 +73,7 @@ ifeq ($(platform), unix) LIBM := endif CFLAGS += $(FORCE_32BIT) - LDFLAGS := -Wl,--no-undefined + LDFLAGS += -Wl,--no-undefined ifeq ($(HAVE_DYNAREC),1) HAVE_MMAP = 1 endif @@ -196,12 +195,20 @@ else ifeq ($(platform), switch) include $(LIBTRANSISTOR_HOME)/libtransistor.mk STATIC_LINKING=1 +# Nintendo Game Cube / Wii / WiiU +else ifneq (,$(filter $(platform), ngc wii wiiu)) + TARGET := $(TARGET_NAME)_libretro_$(platform).a + CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) + AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) + CFLAGS += -DGEKKO -mcpu=750 -meabi -mhard-float -DHAVE_STRTOF_L + STATIC_LINKING = 1 + # PSP else ifeq ($(platform), psp1) TARGET := $(TARGET_NAME)_libretro_$(platform).a CC = psp-gcc$(EXE_EXT) AR = psp-ar$(EXE_EXT) - CFLAGS += -DPSP -G0 -DUSE_BGR_FORMAT + CFLAGS += -DPSP -G0 -DUSE_BGR_FORMAT -DMIPS_HAS_R2_INSTS CFLAGS += -I$(shell psp-config --pspsdk-path)/include CFLAGS += -march=allegrex -mfp32 -mgp32 -mlong32 -mabi=eabi CFLAGS += -fomit-frame-pointer -ffast-math @@ -368,7 +375,7 @@ else ifneq (,$(findstring armv,$(platform))) ifeq (,$(findstring no-dynarec,$(platform))) HAVE_DYNAREC := 1 endif - LDFLAGS := -Wl,--no-undefined + LDFLAGS += -Wl,--no-undefined # MIPS else ifeq ($(platform), mips32) @@ -376,28 +383,26 @@ else ifeq ($(platform), mips32) SHARED := -shared -nostdlib -Wl,--version-script=link.T fpic := -fPIC -DPIC CFLAGS += -fomit-frame-pointer -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float + CFLAGS += -DMIPS_HAS_R2_INSTS HAVE_DYNAREC := 1 CPU_ARCH := mips -# emscripten -else ifeq ($(platform), emscripten) - TARGET := $(TARGET_NAME)_libretro_$(platform).bc - STATIC_LINKING = 1 - -# GCW0 -else ifeq ($(platform), gcw0) +# MIPS64 +else ifeq ($(platform), mips64n32) TARGET := $(TARGET_NAME)_libretro.so - CC = /opt/gcw0-toolchain/usr/bin/mipsel-linux-gcc - CXX = /opt/gcw0-toolchain/usr/bin/mipsel-linux-g++ - AR = /opt/gcw0-toolchain/usr/bin/mipsel-linux-ar SHARED := -shared -nostdlib -Wl,--version-script=link.T fpic := -fPIC -DPIC - CFLAGS += -fomit-frame-pointer -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float + CFLAGS += -fomit-frame-pointer -ffast-math -march=mips64 -mabi=n32 -mhard-float HAVE_DYNAREC := 1 CPU_ARCH := mips -# GCW0 (OpenDingux Beta) -else ifeq ($(platform), gcw0-odbeta) +# emscripten +else ifeq ($(platform), emscripten) + TARGET := $(TARGET_NAME)_libretro_$(platform).bc + STATIC_LINKING = 1 + +# GCW0 (OD and OD Beta) +else ifeq ($(platform), gcw0) TARGET := $(TARGET_NAME)_libretro.so CC = /opt/gcw0-toolchain/usr/bin/mipsel-linux-gcc CXX = /opt/gcw0-toolchain/usr/bin/mipsel-linux-g++ @@ -405,10 +410,7 @@ else ifeq ($(platform), gcw0-odbeta) SHARED := -shared -nostdlib -Wl,--version-script=link.T fpic := -fPIC -DPIC CFLAGS += -fomit-frame-pointer -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float - # The ASM code and/or MIPS dynarec of GPSP does not respect - # MIPS calling conventions, so we must use '-fno-caller-saves' - # for the OpenDingux Beta build - CFLAGS += -fno-caller-saves + CFLAGS += -DMIPS_HAS_R2_INSTS HAVE_DYNAREC := 1 CPU_ARCH := mips @@ -443,11 +445,6 @@ else OPTIMIZE := -O3 -DNDEBUG endif - -include Makefile.common - -OBJECTS := $(SOURCES_C:.c=.o) $(SOURCES_ASM:.S=.o) - DEFINES := -DHAVE_STRINGS_H -DHAVE_STDINT_H -DHAVE_INTTYPES_H -D__LIBRETRO__ -DINLINE=inline -Wall ifeq ($(HAVE_DYNAREC), 1) @@ -462,6 +459,9 @@ else ifeq ($(CPU_ARCH), x86_32) DEFINES += -DX86_ARCH endif +include Makefile.common + +OBJECTS := $(SOURCES_C:.c=.o) $(SOURCES_ASM:.S=.o) WARNINGS_DEFINES = CODE_DEFINES = diff --git a/Makefile.common b/Makefile.common index 0dcbedc..79ae145 100644 --- a/Makefile.common +++ b/Makefile.common @@ -2,9 +2,6 @@ INCFLAGS := -I$(CORE_DIR)/libretro -I$(CORE_DIR)/src SOURCES_ASM := $(CORE_DIR)/bios_data.S -ifeq ($(HAVE_GRIFFIN), 1) -SOURCES_C := $(CORE_DIR)/gpsp_griffin.c -else SOURCES_C := $(CORE_DIR)/main.c \ $(CORE_DIR)/cpu.c \ $(CORE_DIR)/gba_memory.c \ @@ -18,7 +15,6 @@ SOURCES_C := $(CORE_DIR)/main.c \ ifeq ($(HAVE_DYNAREC), 1) SOURCES_C += $(CORE_DIR)/cpu_threaded.c endif -endif ifeq ($(HAVE_DYNAREC), 1) diff --git a/arm/arm_emit.h b/arm/arm_emit.h index 1432617..22ca763 100644 --- a/arm/arm_emit.h +++ b/arm/arm_emit.h @@ -31,6 +31,8 @@ u32 prepare_store_reg(u32 scratch_reg, u32 reg_index); void generate_load_reg(u32 ireg, u32 reg_index); void complete_store_reg(u32 scratch_reg, u32 reg_index); void complete_store_reg_pc_no_flags(u32 scratch_reg, u32 reg_index); +void thumb_cheat_hook(void); +void arm_cheat_hook(void); u32 arm_update_gba_arm(u32 pc); u32 arm_update_gba_thumb(u32 pc); @@ -317,7 +319,7 @@ u32 arm_disect_imm_32bit(u32 imm, u32 *stores, u32 *rotations) #define generate_load_pc(ireg, new_pc) \ - arm_load_imm_32bit(ireg, new_pc) \ + arm_load_imm_32bit(ireg, (new_pc)) \ #define generate_load_imm(ireg, imm, imm_ror) \ ARM_MOV_REG_IMM(0, ireg, imm, imm_ror) \ @@ -1237,12 +1239,10 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address) #define emit_trace_instruction(pc) \ generate_save_flags(); \ - ARM_LDR_IMM(0, ARMREG_SP, reg_base, 34*4); \ ARM_STMDB_WB(0, ARMREG_SP, 0x500C); \ arm_load_imm_32bit(reg_a0, pc); \ generate_function_call(trace_instruction); \ ARM_LDMIA_WB(0, ARMREG_SP, 0x500C); \ - arm_load_imm_32bit(ARMREG_SP, (u32)reg); \ generate_restore_flags(); #define emit_trace_thumb_instruction(pc) \ emit_trace_instruction(pc) @@ -1656,6 +1656,11 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address) /* Operation types: imm, mem_reg, mem_imm */ +#define thumb_load_pc_pool_const(reg_rd, value) \ + u32 rgdst = prepare_store_reg(reg_a0, reg_rd); \ + generate_load_pc(rgdst, (value)); \ + complete_store_reg(rgdst, reg_rd) + #define thumb_access_memory_load(mem_type, _rd) \ cycle_count += 2; \ generate_function_call(execute_load_##mem_type); \ @@ -1876,6 +1881,12 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address) generate_indirect_branch_cycle_update(dual_thumb); \ } \ +#define thumb_process_cheats() \ + generate_function_call(thumb_cheat_hook); + +#define arm_process_cheats() \ + generate_function_call(arm_cheat_hook); + #define thumb_swi() \ generate_swi_hle_handler(opcode & 0xFF, thumb); \ generate_function_call(execute_swi_thumb); \ diff --git a/arm/arm_stub.S b/arm/arm_stub.S index e0f02f4..848d311 100644 --- a/arm/arm_stub.S +++ b/arm/arm_stub.S @@ -67,14 +67,8 @@ _##symbol: #define MODE_SUPERVISOR 3 -#ifdef __ARM_ARCH_7A__ - #define extract_u16(rd, rs) \ - uxth rd, rs -#else - #define extract_u16(rd, rs) \ - bic rd, rs, #0xff000000 ;\ - bic rd, rd, #0x00ff0000 -#endif +#define extract_u16(rd, rs) \ + uxth rd, rs @ Will load the register set from memory into the appropriate cached registers. @ See arm_emit.h for listing explanation. @@ -288,6 +282,22 @@ arm_update_gba_builder(idle_arm, arm, add) arm_update_gba_builder(idle_thumb, thumb, add) +@ Cheat hooks for master function +@ This is called whenever PC == cheats-master-function +@ Just calls the C function to process cheats + +#define cheat_hook_builder(mode) ;\ +defsymbl(mode##_cheat_hook) ;\ + save_flags() ;\ + store_registers_##mode() ;\ + call_c_function(process_cheats) ;\ + load_registers_##mode() ;\ + restore_flags() ;\ + bx lr ;\ + +cheat_hook_builder(arm) +cheat_hook_builder(thumb) + @ These are b stubs for performing indirect branches. They are not @ linked to and don't return, instead they link elsewhere. @@ -763,12 +773,10 @@ lookup_pc: #define sign_extend_u32(reg) #define sign_extend_s8(reg) ;\ - mov reg, reg, lsl #24 /* shift reg into upper 8bits */;\ - mov reg, reg, asr #24 /* shift down, sign extending */;\ + sxtb reg, reg #define sign_extend_s16(reg) ;\ - mov reg, reg, lsl #16 /* shift reg into upper 16bits */;\ - mov reg, reg, asr #16 /* shift down, sign extending */;\ + sxth reg, reg #define execute_load_op_u8(load_op) ;\ mov r0, r0, lsl #17 ;\ @@ -822,11 +830,11 @@ ext_load_##load_type: ;\ .pool -execute_load_builder(u8, 8, ldrneb, #0xF0000000) -execute_load_builder(s8, 8, ldrnesb, #0xF0000000) -execute_load_builder(u16, 16, ldrneh, #0xF0000001) -execute_load_builder(s16, 16_signed, ldrnesh, #0xF0000001) -execute_load_builder(u32, 32, ldrne, #0xF0000000) +execute_load_builder(u8, 8, ldrb, #0xF0000000) +execute_load_builder(s8, 8, ldrsb, #0xF0000000) +execute_load_builder(u16, 16, ldrh, #0xF0000001) +execute_load_builder(s16, 16_signed, ldrsh, #0xF0000001) +execute_load_builder(u32, 32, ldr, #0xF0000003) .data @@ -19,373 +19,247 @@ #include "common.h" -cheat_type cheats[MAX_CHEATS]; -u32 num_cheats; - -void decrypt_gsa_code(u32 *address_ptr, u32 *value_ptr, cheat_variant_enum - cheat_variant) +typedef struct { - u32 i; - u32 address = *address_ptr; - u32 value = *value_ptr; - u32 r = 0xc6ef3720; - - u32 seeds_v1[4] = - { - 0x09f4fbbd, 0x9681884a, 0x352027e9, 0xf3dee5a7 - }; - u32 seeds_v3[4] = - { - 0x7aa9648f, 0x7fae6994, 0xc0efaad5, 0x42712c57 - }; - u32 *seeds; + bool cheat_active; + struct { + u32 address; + u32 value; + } codes[MAX_CHEAT_CODES]; + unsigned cheat_count; +} cheat_type; - if(cheat_variant == CHEAT_TYPE_GAMESHARK_V1) - seeds = seeds_v1; - else - seeds = seeds_v3; +cheat_type cheats[MAX_CHEATS]; +u32 max_cheat = 0; +u32 cheat_master_hook = 0xffffffff; - for(i = 0; i < 32; i++) +static bool has_encrypted_codebreaker(cheat_type *cheat) +{ + int i; + for(i = 0; i < cheat->cheat_count; i++) { - value -= ((address << 4) + seeds[2]) ^ (address + r) ^ - ((address >> 5) + seeds[3]); - address -= ((value << 4) + seeds[0]) ^ (value + r) ^ - ((value >> 5) + seeds[1]); - r -= 0x9e3779b9; + u32 code = cheat->codes[i].address; + u32 opcode = code >> 28; + if (opcode == 9) + return true; } - - *address_ptr = address; - *value_ptr = value; + return false; } -void add_cheats(char *cheats_filename) +static void update_hook_codebreaker(cheat_type *cheat) { - FILE *cheats_file; - char current_line[256]; - char *name_ptr; - u32 *cheat_code_ptr; - u32 address, value; - u32 num_cheat_lines; - u32 cheat_name_length; - cheat_variant_enum current_cheat_variant; - - num_cheats = 0; - - cheats_file = fopen(cheats_filename, "rb"); - - if(cheats_file) + int i; + for(i = 0; i < cheat->cheat_count; i++) { - while(fgets(current_line, 256, cheats_file)) - { - // Get the header line first - name_ptr = strchr(current_line, ' '); - if(name_ptr) - { - *name_ptr = 0; - name_ptr++; - } - - if(!strcasecmp(current_line, "gameshark_v1") || - !strcasecmp(current_line, "gameshark_v2") || - !strcasecmp(current_line, "PAR_v1") || - !strcasecmp(current_line, "PAR_v2")) - { - current_cheat_variant = CHEAT_TYPE_GAMESHARK_V1; - } - else - - if(!strcasecmp(current_line, "gameshark_v3") || - !strcasecmp(current_line, "PAR_v3")) - { - current_cheat_variant = CHEAT_TYPE_GAMESHARK_V3; - } - else - { - current_cheat_variant = CHEAT_TYPE_INVALID; - } - - if(current_cheat_variant != CHEAT_TYPE_INVALID) - { - strncpy(cheats[num_cheats].cheat_name, name_ptr, CHEAT_NAME_LENGTH - 1); - cheats[num_cheats].cheat_name[CHEAT_NAME_LENGTH - 1] = 0; - cheat_name_length = strlen(cheats[num_cheats].cheat_name); - if(cheat_name_length && - ((cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\n') || - (cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\r'))) - { - cheats[num_cheats].cheat_name[cheat_name_length - 1] = 0; - cheat_name_length--; - } - - if(cheat_name_length && - cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\r') - { - cheats[num_cheats].cheat_name[cheat_name_length - 1] = 0; - } - - cheats[num_cheats].cheat_variant = current_cheat_variant; - cheat_code_ptr = cheats[num_cheats].cheat_codes; - num_cheat_lines = 0; - - while(fgets(current_line, 256, cheats_file)) - { - if(strlen(current_line) < 3) - break; - - sscanf(current_line, "%08x %08x", &address, &value); - - decrypt_gsa_code(&address, &value, current_cheat_variant); - - cheat_code_ptr[0] = address; - cheat_code_ptr[1] = value; - - cheat_code_ptr += 2; - num_cheat_lines++; - } - - cheats[num_cheats].num_cheat_lines = num_cheat_lines; - - num_cheats++; - } - } - - fclose(cheats_file); + u32 code = cheat->codes[i].address; + u32 address = code & 0xfffffff; + u32 opcode = code >> 28; + + if (opcode == 1) + { + u32 pcaddr = 0x08000000 | (address & 0x1ffffff); + #ifdef HAVE_DYNAREC + if (cheat_master_hook != pcaddr) + init_caches(); /* Flush caches to install hook */ + #endif + cheat_master_hook = pcaddr; + return; /* Only support for one hook */ + } } } -void process_cheat_gs1(cheat_type *cheat) +static void process_cheat_codebreaker(cheat_type *cheat, u16 pad) { - u32 cheat_opcode; - u32 *code_ptr = cheat->cheat_codes; - u32 address, value; - u32 i; - - for(i = 0; i < cheat->num_cheat_lines; i++) + int i; + unsigned j; + for(i = 0; i < cheat->cheat_count; i++) { - address = code_ptr[0]; - value = code_ptr[1]; - - code_ptr += 2; - - cheat_opcode = address >> 28; - address &= 0xFFFFFFF; - - switch(cheat_opcode) - { - case 0x0: - write_memory8(address, value); - break; - - case 0x1: - write_memory16(address, value); - break; - - case 0x2: - write_memory32(address, value); - break; - - case 0x3: + u32 code = cheat->codes[i].address; + u16 value = cheat->codes[i].value; + u32 address = code & 0xfffffff; + u32 opcode = code >> 28; + + switch (opcode) { + case 0: /* Game CRC, ignored for now */ + break; + case 1: /* Master code function */ + break; + case 2: /* 16 bit OR */ + write_memory16(address, read_memory16(address) | value); + break; + case 3: /* 8 bit write */ + write_memory8(address, value); + break; + case 4: /* Slide code, writes a buffer with addr/value strides */ + if (i + 1 < cheat->cheat_count) { - u32 num_addresses = address & 0xFFFF; - u32 address1, address2; - u32 i2; - - for(i2 = 0; i2 < num_addresses; i2++) + u16 count = cheat->codes[++i].address; + u16 vincr = cheat->codes[ i].address >> 16; + u16 aincr = cheat->codes[ i].value; + for (j = 0; j < count; j++) { - address1 = code_ptr[0]; - address2 = code_ptr[1]; - code_ptr += 2; - i++; - - write_memory32(address1, value); - if(address2 != 0) - write_memory32(address2, value); + write_memory16(address, value); + address += aincr; + value += vincr; } - break; } - - // ROM patch not supported yet - case 0x6: - break; - - // GS button down not supported yet - case 0x8: - break; - - // Reencryption (DEADFACE) not supported yet - case 0xD: - if(read_memory16(address) != (value & 0xFFFF)) - { - code_ptr += 2; + break; + case 5: /* Super code: copies bytes to a buffer addr */ + for (j = 0; j < value * 2 && i < cheat->cheat_count; j++) + { + u8 bvalue, off = j % 6; + switch (off) { + case 0: + bvalue = cheat->codes[++i].address >> 24; + break; + case 1 ... 3: + bvalue = cheat->codes[i].address >> (24 - off*8); + break; + case 4 ... 5: + bvalue = cheat->codes[i].value >> (40 - off*8); + break; + }; + write_memory8(address, bvalue); + address++; + } + break; + case 6: /* 16 bit AND */ + write_memory16(address, read_memory16(address) & value); + break; + case 7: /* Compare mem value and execute next cheat */ + if (read_memory16(address) != value) + i++; + break; + case 8: /* 16 bit write */ + write_memory16(address, value); + break; + case 10: /* Compare mem value and skip next cheat */ + if (read_memory16(address) == value) + i++; + break; + case 11: /* Compare mem value and skip next cheat */ + if (read_memory16(address) <= value) + i++; + break; + case 12: /* Compare mem value and skip next cheat */ + if (read_memory16(address) >= value) + i++; + break; + case 13: /* Check button state and execute next cheat */ + switch ((address >> 4) & 0xf) { + case 0: + if (((~pad) & 0x3ff) == value) i++; - } break; - - case 0xE: - if(read_memory16(value & 0xFFFFFFF) != (address & 0xFFFF)) - { - u32 skip = ((address >> 16) & 0x03); - code_ptr += skip * 2; - i += skip; - } + case 1: + if ((pad & value) == value) + i++; break; - - // Hook routine not supported yet (not important??) - case 0x0F: + case 2: + if ((pad & value) == 0) + i++; break; + }; + break; + case 14: /* Increase 16/32 bit memory value */ + if (address & 1) + { + u32 value32 = (u32)((s16)value); /* Sign extend to 32 bit */ + address &= ~1U; + write_memory32(address, read_memory32(address) + value32); + } + else + { + write_memory16(address, read_memory16(address) + value); + } + break; + case 15: /* Immediate and check and skip */ + if ((read_memory16(address) & value) == 0) + i++; + break; } } } -// These are especially incomplete. - -void process_cheat_gs3(cheat_type *cheat) +void process_cheats(void) { - u32 cheat_opcode; - u32 *code_ptr = cheat->cheat_codes; - u32 address, value; - u32 i; - - for(i = 0; i < cheat->num_cheat_lines; i++) - { - address = code_ptr[0]; - value = code_ptr[1]; - - code_ptr += 2; - - cheat_opcode = address >> 28; - address &= 0xFFFFFFF; - - switch(cheat_opcode) - { - case 0x0: - cheat_opcode = address >> 24; - address = (address & 0xFFFFF) + ((address << 4) & 0xF000000); - - switch(cheat_opcode) - { - case 0x0: - { - u32 iterations = value >> 24; - u32 i2; - - value &= 0xFF; - - for(i2 = 0; i2 <= iterations; i2++, address++) - { - write_memory8(address, value); - } - break; - } - - case 0x2: - { - u32 iterations = value >> 16; - u32 i2; - - value &= 0xFFFF; - - for(i2 = 0; i2 <= iterations; i2++, address += 2) - { - write_memory16(address, value); - } - break; - } - - case 0x4: - write_memory32(address, value); - break; - } - break; - - case 0x4: - cheat_opcode = address >> 24; - address = (address & 0xFFFFF) + ((address << 4) & 0xF000000); - - switch(cheat_opcode) - { - case 0x0: - address = read_memory32(address) + (value >> 24); - write_memory8(address, value & 0xFF); - break; - - case 0x2: - address = read_memory32(address) + ((value >> 16) * 2); - write_memory16(address, value & 0xFFFF); - break; - - case 0x4: - address = read_memory32(address); - write_memory32(address, value); - break; - - } - break; - - case 0x8: - cheat_opcode = address >> 24; - address = (address & 0xFFFFF) + ((address << 4) & 0xF000000); - - switch(cheat_opcode) - { - case 0x0: - value = (value & 0xFF) + read_memory8(address); - write_memory8(address, value); - break; + u32 i; - case 0x2: - value = (value & 0xFFFF) + read_memory16(address); - write_memory16(address, value); - break; + for(i = 0; i <= max_cheat; i++) + { + if(!cheats[i].cheat_active) + continue; - case 0x4: - value = value + read_memory32(address); - write_memory32(address, value); - break; - } - break; - - case 0xC: - cheat_opcode = address >> 24; - address = (address & 0xFFFFFF) + 0x4000000; - - switch(cheat_opcode) - { - case 0x6: - write_memory16(address, value); - break; - - case 0x7: - write_memory32(address, value); - break; - } - break; - } - } + process_cheat_codebreaker(&cheats[i], 0x3ff ^ read_ioreg(REG_P1)); + } } - -void process_cheats(void) +void cheat_clear() { - u32 i; + int i; + for (i = 0; i < MAX_CHEATS; i++) + { + cheats[i].cheat_count = 0; + cheats[i].cheat_active = false; + } + cheat_master_hook = 0xffffffff; +} - for(i = 0; i < num_cheats; i++) - { - if(cheats[i].cheat_active) - { - switch(cheats[i].cheat_variant) - { - case CHEAT_TYPE_GAMESHARK_V1: - process_cheat_gs1(cheats + i); - break; +cheat_error cheat_parse(unsigned index, const char *code) +{ + int pos = 0; + int codelen = strlen(code); + cheat_type *ch = &cheats[index]; + char buf[1024]; + + if (index >= MAX_CHEATS) + return CheatErrorTooMany; + if (codelen >= sizeof(buf)) + return CheatErrorTooBig; + + memcpy(buf, code, codelen+1); + + /* Init to a known good state */ + ch->cheat_count = 0; + if (index > max_cheat) + max_cheat = index; + + /* Replace all the non-hex chars to spaces */ + for (pos = 0; pos < codelen; pos++) + if (!((buf[pos] >= '0' && buf[pos] <= '9') || + (buf[pos] >= 'a' && buf[pos] <= 'f') || + (buf[pos] >= 'A' && buf[pos] <= 'F'))) + buf[pos] = ' '; + + /* Try to parse as Code Breaker */ + pos = 0; + while (pos < codelen) + { + u32 op1; u16 op2; + if (2 != sscanf(&buf[pos], "%08x %04hx", &op1, &op2)) + break; + ch->codes[ch->cheat_count].address = op1; + ch->codes[ch->cheat_count++].value = op2; + pos += 13; + while (pos < codelen && buf[pos] == ' ') + pos++; + if (ch->cheat_count >= MAX_CHEAT_CODES) + break; + } + + if (pos >= codelen) + { + /* Check whether these cheats are readable */ + if (has_encrypted_codebreaker(ch)) + return CheatErrorEncrypted; + /* All codes were parsed! Process hook here */ + ch->cheat_active = true; + update_hook_codebreaker(ch); + return CheatNoError; + } + + /* TODO parse other types here */ + return CheatErrorNotSupported; +} - case CHEAT_TYPE_GAMESHARK_V3: - process_cheat_gs3(cheats + i); - break; - default: - break; - } - } - } -} @@ -17,28 +17,25 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#define CHEAT_NAME_LENGTH 17 +#ifndef __GPSP_CHEATS_H__ +#define __GPSP_CHEATS_H__ -typedef enum -{ - CHEAT_TYPE_GAMESHARK_V1, - CHEAT_TYPE_GAMESHARK_V3, - CHEAT_TYPE_INVALID -} cheat_variant_enum; +#define MAX_CHEATS 20 +#define MAX_CHEAT_CODES 64 -typedef struct -{ - char cheat_name[CHEAT_NAME_LENGTH]; - u32 cheat_active; - u32 cheat_codes[256]; - u32 num_cheat_lines; - cheat_variant_enum cheat_variant; -} cheat_type; +typedef enum { + CheatNoError = 0, + CheatErrorTooMany, + CheatErrorTooBig, + CheatErrorEncrypted, + CheatErrorNotSupported +} cheat_error; void process_cheats(void); -void add_cheats(char *cheats_filename); +cheat_error cheat_parse(unsigned index, const char *code); +void cheat_clear(void); -#define MAX_CHEATS 16 +extern u32 cheat_master_hook; + +#endif -extern cheat_type cheats[MAX_CHEATS]; -extern u32 num_cheats; @@ -128,6 +128,22 @@ typedef u32 fixed8_24; #define address32(base, offset) \ *((u32 *)((u8 *)base + (offset))) \ +#define eswap8(value) (value) +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + #define eswap16(value) __builtin_bswap16(value) + #define eswap32(value) __builtin_bswap32(value) +#else + #define eswap16(value) (value) + #define eswap32(value) (value) +#endif + +#define readaddress8(base, offset) eswap8( address8( base, offset)) +#define readaddress16(base, offset) eswap16(address16(base, offset)) +#define readaddress32(base, offset) eswap32(address32(base, offset)) + +#define read_ioreg(regnum) (eswap16(io_registers[(regnum)])) +#define write_ioreg(regnum, val) io_registers[(regnum)] = eswap16(val) + #include <unistd.h> #include <time.h> #include <stdlib.h> @@ -266,7 +266,7 @@ void print_register_usage(void) using_register_list(arm, reg_list, 16) \ #define arm_decode_branch() \ - s32 offset = ((s32)(opcode & 0xFFFFFF) << 8) >> 6 \ + s32 offset = ((s32)((u32)(opcode << 8))) >> 6 \ #define thumb_decode_shift() \ @@ -684,14 +684,6 @@ void print_register_usage(void) reg[REG_CPSR] = (n_flag << 31) | (z_flag << 30) | (c_flag << 29) | \ (v_flag << 28) | (reg[REG_CPSR] & 0xFF) \ -#define memory_region(r_dest, l_dest, address) \ - r_dest = memory_regions[address >> 24]; \ - l_dest = memory_limits[address >> 24] \ - - -#define pc_region() \ - memory_region(pc_region, pc_limit, pc) \ - #define check_pc_region() \ new_pc_region = (pc >> 15); \ if(new_pc_region != pc_region) \ @@ -729,8 +721,8 @@ u32 high_frequency_branch_targets = 0; // probably not worth optimizing for. #define check_for_interrupts() \ - if((io_registers[REG_IE] & io_registers[REG_IF]) && \ - io_registers[REG_IME] && ((reg[REG_CPSR] & 0x80) == 0)) \ + if((read_ioreg(REG_IE) & read_ioreg(REG_IF)) && \ + read_ioreg(REG_IME) && ((reg[REG_CPSR] & 0x80) == 0)) \ { \ reg_mode[MODE_IRQ][6] = reg[REG_PC] + 4; \ spsr[MODE_IRQ] = reg[REG_CPSR]; \ @@ -953,10 +945,10 @@ const u32 psr_masks[16] = #define aligned_address_mask16 0xF0000001 #define aligned_address_mask32 0xF0000003 -#define fast_read_memory(size, type, address, dest) \ +#define fast_read_memory(size, type, addr, dest) \ { \ u8 *map; \ - u32 _address = address; \ + u32 _address = addr; \ \ if(_address < 0x10000000) \ { \ @@ -972,7 +964,7 @@ const u32 psr_masks[16] = if(((_address & aligned_address_mask##size) == 0) && \ (map = memory_map_read[_address >> 15])) \ { \ - dest = *((type *)((u8 *)map + (_address & 0x7FFF))); \ + dest = (type)readaddress##size(map, (_address & 0x7FFF)); \ } \ else \ { \ @@ -992,7 +984,7 @@ const u32 psr_masks[16] = if(((_address & aligned_address_mask16) == 0) && \ (map = memory_map_read[_address >> 15])) \ { \ - dest = *((s16 *)((u8 *)map + (_address & 0x7FFF))); \ + dest = (s16)readaddress16(map, (_address & 0x7FFF)); \ } \ else \ { \ @@ -1024,9 +1016,9 @@ const u32 psr_masks[16] = memory_region_access_read_u32[_address >> 24]++; \ memory_reads_u32++; \ } \ - if(map) \ + if(_address < 0x10000000 && map) \ { \ - dest = address32(map, _address & 0x7FFF); \ + dest = readaddress32(map, _address & 0x7FFF); \ } \ else \ { \ @@ -1131,10 +1123,10 @@ const u32 psr_masks[16] = #define arm_block_writeback_no(access_type) \ #define load_block_memory(address, dest) \ - dest = address32(address_region, (address + offset) & 0x7FFF) \ + dest = readaddress32(address_region, (address + offset) & 0x7FFF) \ #define store_block_memory(address, dest) \ - address32(address_region, (address + offset) & 0x7FFF) = dest \ + address32(address_region, (address + offset) & 0x7FFF) = eswap32(dest) \ #define arm_block_memory_offset_down_a() \ (base - (word_bit_count(reg_list) * 4) + 4) \ @@ -1609,9 +1601,9 @@ void raise_interrupt(irq_type irq_raised) { // The specific IRQ must be enabled in IE, master IRQ enable must be on, // and it must be on in the flags. - io_registers[REG_IF] |= irq_raised; + write_ioreg(REG_IF, read_ioreg(REG_IF) | irq_raised); - if((io_registers[REG_IE] & irq_raised) && io_registers[REG_IME] && + if((read_ioreg(REG_IE) & irq_raised) && read_ioreg(REG_IME) && ((reg[REG_CPSR] & 0x80) == 0)) { bios_read_protect = 0xe55ec002; @@ -1681,13 +1673,17 @@ arm_loop: collapse_flags(); cycles_per_instruction = global_cycles_per_instruction; + /* Process cheats if we are about to execute the cheat hook */ + if (pc == cheat_master_hook) + process_cheats(); + old_pc = pc; /* Execute ARM instruction */ using_instruction(arm); check_pc_region(); pc &= ~0x03; - opcode = address32(pc_address_block, (pc & 0x7FFF)); + opcode = readaddress32(pc_address_block, (pc & 0x7FFF)); condition = opcode >> 28; switch(condition) @@ -1712,2542 +1708,2032 @@ arm_loop: if(c_flag) arm_next_instruction(); break; - case 0x4: - /* MI */ - if(!n_flag) - arm_next_instruction(); - break; - - case 0x5: - /* PL */ - if(n_flag) - arm_next_instruction(); - break; - - case 0x6: - /* VS */ - if(!v_flag) - arm_next_instruction(); - break; - - case 0x7: - /* VC */ - if(v_flag) - arm_next_instruction(); - break; - - case 0x8: - /* HI */ - if((c_flag == 0) | z_flag) - arm_next_instruction(); - break; - - case 0x9: - /* LS */ - if(c_flag & (z_flag ^ 1)) - arm_next_instruction(); - break; - - case 0xA: - /* GE */ - if(n_flag != v_flag) - arm_next_instruction(); - break; - - case 0xB: - /* LT */ - if(n_flag == v_flag) - arm_next_instruction(); - break; - - case 0xC: - /* GT */ - if(z_flag | (n_flag != v_flag)) - arm_next_instruction(); - break; - - case 0xD: - /* LE */ - if((z_flag == 0) & (n_flag == v_flag)) - arm_next_instruction(); - break; - - case 0xE: - /* AL */ - break; - - case 0xF: - /* Reserved - treat as "never" */ - arm_next_instruction(); - break; - } - - switch((opcode >> 20) & 0xFF) - { - case 0x00: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], -rm */ - arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); - } - else - { - /* MUL rd, rm, rs */ - arm_multiply(no_op, no); - } - } - else - { - /* AND rd, rn, reg_op */ - arm_data_proc(reg[rn] & reg_sh, reg); - } - break; - - case 0x01: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* MULS rd, rm, rs */ - arm_multiply(no_op, yes); - break; - - case 1: - /* LDRH rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); - break; - - case 2: - /* LDRSB rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); - break; - - case 3: - /* LDRSH rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); - break; - } - } - else - { - /* ANDS rd, rn, reg_op */ - arm_data_proc_logic_flags(reg[rn] & reg_sh, reg); - } - break; - - case 0x02: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], -rm */ - arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); - } - else - { - /* MLA rd, rm, rs, rn */ - arm_multiply(+ reg[rn], no); - } - } - else - { - /* EOR rd, rn, reg_op */ - arm_data_proc(reg[rn] ^ reg_sh, reg); - } - break; - - case 0x03: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* MLAS rd, rm, rs, rn */ - arm_multiply(+ reg[rn], yes); - break; - - case 1: - /* LDRH rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); - break; - - case 2: - /* LDRSB rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); - break; - - case 3: - /* LDRSH rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); - break; - } - } - else - { - /* EORS rd, rn, reg_op */ - arm_data_proc_logic_flags(reg[rn] ^ reg_sh, reg); - } - break; - - case 0x04: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn], -imm */ - arm_access_memory(store, no_op, half_imm, u16, yes, - offset); - } - else - { - /* SUB rd, rn, reg_op */ - arm_data_proc(reg[rn] - reg_sh, reg); - } - break; - - case 0x05: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, u16, yes, - offset); - break; - - case 2: - /* LDRSB rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, s8, yes, - offset); - break; - - case 3: - /* LDRSH rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, s16, yes, - offset); - break; - } - } - else - { - /* SUBS rd, rn, reg_op */ - arm_data_proc_sub_flags(reg[rn], reg_sh, reg); - } - break; - - case 0x06: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn], -imm */ - arm_access_memory(store, no_op, half_imm, u16, yes, - offset); - } - else - { - /* RSB rd, rn, reg_op */ - arm_data_proc(reg_sh - reg[rn], reg); - } - break; - - case 0x07: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, u16, yes, - offset); - break; - - case 2: - /* LDRSB rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, s8, yes, - offset); - break; - - case 3: - /* LDRSH rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, s16, yes, - offset); - break; - } - } - else - { - /* RSBS rd, rn, reg_op */ - arm_data_proc_sub_flags(reg_sh, reg[rn], reg); - } - break; - - case 0x08: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], +rm */ - arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); - } - else - { - /* UMULL rd, rm, rs */ - arm_multiply_long(no_op, no, u); - } - } - else - { - /* ADD rd, rn, reg_op */ - arm_data_proc(reg[rn] + reg_sh, reg); - } - break; - - case 0x09: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* UMULLS rdlo, rdhi, rm, rs */ - arm_multiply_long(no_op, yes, u); - break; - - case 1: - /* LDRH rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); - break; - - case 2: - /* LDRSB rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); - break; - - case 3: - /* LDRSH rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); - break; - } - } - else - { - /* ADDS rd, rn, reg_op */ - arm_data_proc_add_flags(reg[rn], reg_sh, reg); - } - break; - - case 0x0A: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], +rm */ - arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); - } - else - { - /* UMLAL rd, rm, rs */ - arm_multiply_long(arm_multiply_long_addop(u), no, u); - } - } - else - { - /* ADC rd, rn, reg_op */ - arm_data_proc(reg[rn] + reg_sh + c_flag, reg); - } - break; - - case 0x0B: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* UMLALS rdlo, rdhi, rm, rs */ - arm_multiply_long(arm_multiply_long_addop(u), yes, u); - break; - - case 1: - /* LDRH rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); - break; - - case 2: - /* LDRSB rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); - break; - - case 3: - /* LDRSH rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); - break; - } - } - else - { - /* ADCS rd, rn, reg_op */ - arm_data_proc_add_flags(reg[rn], reg_sh + c_flag, reg); - } - break; - - case 0x0C: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], +imm */ - arm_access_memory(store, no_op, half_imm, u16, yes, + offset); - } - else - { - /* SMULL rd, rm, rs */ - arm_multiply_long(no_op, no, s); - } - } - else - { - /* SBC rd, rn, reg_op */ - arm_data_proc(reg[rn] - (reg_sh + (c_flag ^ 1)), reg); - } - break; - - case 0x0D: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* SMULLS rdlo, rdhi, rm, rs */ - arm_multiply_long(no_op, yes, s); - break; - - case 1: - /* LDRH rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, u16, yes, + offset); - break; - - case 2: - /* LDRSB rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, s8, yes, + offset); - break; - - case 3: - /* LDRSH rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, s16, yes, + offset); - break; - } - } - else - { - /* SBCS rd, rn, reg_op */ - arm_data_proc_sub_flags(reg[rn], (reg_sh + (c_flag ^ 1)), reg); - } - break; - - case 0x0E: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], +imm */ - arm_access_memory(store, no_op, half_imm, u16, yes, + offset); - } - else - { - /* SMLAL rd, rm, rs */ - arm_multiply_long(arm_multiply_long_addop(s), no, s); - } - } - else - { - /* RSC rd, rn, reg_op */ - arm_data_proc(reg_sh - reg[rn] + c_flag - 1, reg); - } - break; - - case 0x0F: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* SMLALS rdlo, rdhi, rm, rs */ - arm_multiply_long(arm_multiply_long_addop(s), yes, s); - break; - - case 1: - /* LDRH rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, u16, yes, + offset); - break; - - case 2: - /* LDRSB rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, s8, yes, + offset); - break; - - case 3: - /* LDRSH rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, s16, yes, + offset); - break; - } - } - else - { - /* RSCS rd, rn, reg_op */ - arm_data_proc_sub_flags((reg_sh + c_flag - 1), reg[rn], reg); - } - break; - - case 0x10: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn - rm] */ - arm_access_memory(store, - reg[rm], half_reg, u16, no, no_op); - } - else - { - /* SWP rd, rm, [rn] */ - arm_swap(u32); - } - } - else - { - /* MRS rd, cpsr */ - arm_psr(reg, read, reg[REG_CPSR]); - } - break; - - case 0x11: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn - rm] */ - arm_access_memory(load, - reg[rm], half_reg, u16, no, no_op); - break; - - case 2: - /* LDRSB rd, [rn - rm] */ - arm_access_memory(load, - reg[rm], half_reg, s8, no, no_op); - break; - - case 3: - /* LDRSH rd, [rn - rm] */ - arm_access_memory(load, - reg[rm], half_reg, s16, no, no_op); - break; - } - } - else - { - /* TST rd, rn, reg_op */ - arm_data_proc_test_logic(reg[rn] & reg_sh, reg); - } - break; - - case 0x12: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn - rm]! */ - arm_access_memory(store, - reg[rm], half_reg, u16, yes, no_op); - } - else - { - if(opcode & 0x10) - { - /* BX rn */ - arm_decode_branchx(opcode); - u32 src = reg[rn]; - if(src & 0x01) - { - src -= 1; - arm_pc_offset_update_direct(src); - reg[REG_CPSR] |= 0x20; - goto thumb_loop; - } - else - { - arm_pc_offset_update_direct(src); - } - } - else - { - /* MSR cpsr, rm */ - arm_psr(reg, store, cpsr); - } - } - break; - - case 0x13: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn - rm]! */ - arm_access_memory(load, - reg[rm], half_reg, u16, yes, no_op); - break; - - case 2: - /* LDRSB rd, [rn - rm]! */ - arm_access_memory(load, - reg[rm], half_reg, s8, yes, no_op); - break; - - case 3: - /* LDRSH rd, [rn - rm]! */ - arm_access_memory(load, - reg[rm], half_reg, s16, yes, no_op); - break; - } - } - else - { - /* TEQ rd, rn, reg_op */ - arm_data_proc_test_logic(reg[rn] ^ reg_sh, reg); - } - break; - - case 0x14: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn - imm] */ - arm_access_memory(store, - offset, half_imm, u16, no, no_op); - } - else - { - /* SWPB rd, rm, [rn] */ - arm_swap(u8); - } - } - else - { - /* MRS rd, spsr */ - arm_psr(reg, read, spsr[reg[CPU_MODE]]); - } - break; - - case 0x15: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn - imm] */ - arm_access_memory(load, - offset, half_imm, u16, no, no_op); - break; - - case 2: - /* LDRSB rd, [rn - imm] */ - arm_access_memory(load, - offset, half_imm, s8, no, no_op); - break; - - case 3: - /* LDRSH rd, [rn - imm] */ - arm_access_memory(load, - offset, half_imm, s16, no, no_op); - break; - } - } - else - { - /* CMP rn, reg_op */ - arm_data_proc_test_sub(reg[rn], reg_sh, reg); - } - break; - - case 0x16: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn - imm]! */ - arm_access_memory(store, - offset, half_imm, u16, yes, no_op); - } - else - { - /* MSR spsr, rm */ - arm_psr(reg, store, spsr); - } - break; - - case 0x17: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn - imm]! */ - arm_access_memory(load, - offset, half_imm, u16, yes, no_op); - break; - - case 2: - /* LDRSB rd, [rn - imm]! */ - arm_access_memory(load, - offset, half_imm, s8, yes, no_op); - break; - - case 3: - /* LDRSH rd, [rn - imm]! */ - arm_access_memory(load, - offset, half_imm, s16, yes, no_op); - break; - } - } - else - { - /* CMN rd, rn, reg_op */ - arm_data_proc_test_add(reg[rn], reg_sh, reg); - } - break; - - case 0x18: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn + rm] */ - arm_access_memory(store, + reg[rm], half_reg, u16, no, no_op); - } - else - { - /* ORR rd, rn, reg_op */ - arm_data_proc(reg[rn] | reg_sh, reg); - } - break; - - case 0x19: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn + rm] */ - arm_access_memory(load, + reg[rm], half_reg, u16, no, no_op); - break; - - case 2: - /* LDRSB rd, [rn + rm] */ - arm_access_memory(load, + reg[rm], half_reg, s8, no, no_op); - break; - - case 3: - /* LDRSH rd, [rn + rm] */ - arm_access_memory(load, + reg[rm], half_reg, s16, no, no_op); - break; - } - } - else - { - /* ORRS rd, rn, reg_op */ - arm_data_proc_logic_flags(reg[rn] | reg_sh, reg); - } - break; - - case 0x1A: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn + rm]! */ - arm_access_memory(store, + reg[rm], half_reg, u16, yes, no_op); - } - else - { - /* MOV rd, reg_op */ - arm_data_proc(reg_sh, reg); - } - break; - - case 0x1B: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn + rm]! */ - arm_access_memory(load, + reg[rm], half_reg, u16, yes, no_op); - break; - - case 2: - /* LDRSB rd, [rn + rm]! */ - arm_access_memory(load, + reg[rm], half_reg, s8, yes, no_op); - break; - - case 3: - /* LDRSH rd, [rn + rm]! */ - arm_access_memory(load, + reg[rm], half_reg, s16, yes, no_op); - break; - } - } - else - { - /* MOVS rd, reg_op */ - arm_data_proc_logic_flags(reg_sh, reg); - } - break; - - case 0x1C: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn + imm] */ - arm_access_memory(store, + offset, half_imm, u16, no, no_op); - } - else - { - /* BIC rd, rn, reg_op */ - arm_data_proc(reg[rn] & (~reg_sh), reg); - } - break; - - case 0x1D: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn + imm] */ - arm_access_memory(load, + offset, half_imm, u16, no, no_op); - break; - - case 2: - /* LDRSB rd, [rn + imm] */ - arm_access_memory(load, + offset, half_imm, s8, no, no_op); - break; - - case 3: - /* LDRSH rd, [rn + imm] */ - arm_access_memory(load, + offset, half_imm, s16, no, no_op); - break; - } - } - else - { - /* BICS rd, rn, reg_op */ - arm_data_proc_logic_flags(reg[rn] & (~reg_sh), reg); - } - break; - - case 0x1E: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn + imm]! */ - arm_access_memory(store, + offset, half_imm, u16, yes, no_op); - } - else - { - /* MVN rd, reg_op */ - arm_data_proc(~reg_sh, reg); - } - break; - - case 0x1F: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn + imm]! */ - arm_access_memory(load, + offset, half_imm, u16, yes, no_op); - break; - - case 2: - /* LDRSB rd, [rn + imm]! */ - arm_access_memory(load, + offset, half_imm, s8, yes, no_op); - break; - - case 3: - /* LDRSH rd, [rn + imm]! */ - arm_access_memory(load, + offset, half_imm, s16, yes, no_op); - break; - } - } - else - { - /* MVNS rd, rn, reg_op */ - arm_data_proc_logic_flags(~reg_sh, reg); - } - break; - - case 0x20: - /* AND rd, rn, imm */ - arm_data_proc(reg[rn] & imm, imm); - break; - - case 0x21: - /* ANDS rd, rn, imm */ - arm_data_proc_logic_flags(reg[rn] & imm, imm); - break; - - case 0x22: - /* EOR rd, rn, imm */ - arm_data_proc(reg[rn] ^ imm, imm); - break; - - case 0x23: - /* EORS rd, rn, imm */ - arm_data_proc_logic_flags(reg[rn] ^ imm, imm); - break; - - case 0x24: - /* SUB rd, rn, imm */ - arm_data_proc(reg[rn] - imm, imm); - break; - - case 0x25: - /* SUBS rd, rn, imm */ - arm_data_proc_sub_flags(reg[rn], imm, imm); - break; - - case 0x26: - /* RSB rd, rn, imm */ - arm_data_proc(imm - reg[rn], imm); - break; - - case 0x27: - /* RSBS rd, rn, imm */ - arm_data_proc_sub_flags(imm, reg[rn], imm); - break; - - case 0x28: - /* ADD rd, rn, imm */ - arm_data_proc(reg[rn] + imm, imm); - break; - - case 0x29: - /* ADDS rd, rn, imm */ - arm_data_proc_add_flags(reg[rn], imm, imm); - break; - - case 0x2A: - /* ADC rd, rn, imm */ - arm_data_proc(reg[rn] + imm + c_flag, imm); - break; - - case 0x2B: - /* ADCS rd, rn, imm */ - arm_data_proc_add_flags(reg[rn] + imm, c_flag, imm); - break; - - case 0x2C: - /* SBC rd, rn, imm */ - arm_data_proc(reg[rn] - imm + c_flag - 1, imm); - break; - - case 0x2D: - /* SBCS rd, rn, imm */ - arm_data_proc_sub_flags(reg[rn], (imm + (c_flag ^ 1)), imm); - break; - - case 0x2E: - /* RSC rd, rn, imm */ - arm_data_proc(imm - reg[rn] + c_flag - 1, imm); - break; - - case 0x2F: - /* RSCS rd, rn, imm */ - arm_data_proc_sub_flags((imm + c_flag - 1), reg[rn], imm); - break; - - case 0x30: - case 0x31: - /* TST rn, imm */ - arm_data_proc_test_logic(reg[rn] & imm, imm); - break; - - case 0x32: - /* MSR cpsr, imm */ - arm_psr(imm, store, cpsr); - break; - - case 0x33: - /* TEQ rn, imm */ - arm_data_proc_test_logic(reg[rn] ^ imm, imm); - break; - - case 0x34: - case 0x35: - /* CMP rn, imm */ - arm_data_proc_test_sub(reg[rn], imm, imm); - break; - - case 0x36: - /* MSR spsr, imm */ - arm_psr(imm, store, spsr); - break; - - case 0x37: - /* CMN rn, imm */ - arm_data_proc_test_add(reg[rn], imm, imm); - break; - - case 0x38: - /* ORR rd, rn, imm */ - arm_data_proc(reg[rn] | imm, imm); - break; - - case 0x39: - /* ORRS rd, rn, imm */ - arm_data_proc_logic_flags(reg[rn] | imm, imm); - break; - - case 0x3A: - /* MOV rd, imm */ - arm_data_proc(imm, imm); - break; - - case 0x3B: - /* MOVS rd, imm */ - arm_data_proc_logic_flags(imm, imm); - break; - - case 0x3C: - /* BIC rd, rn, imm */ - arm_data_proc(reg[rn] & (~imm), imm); - break; - - case 0x3D: - /* BICS rd, rn, imm */ - arm_data_proc_logic_flags(reg[rn] & (~imm), imm); - break; - - case 0x3E: - /* MVN rd, imm */ - arm_data_proc(~imm, imm); - break; - - case 0x3F: - /* MVNS rd, imm */ - arm_data_proc_logic_flags(~imm, imm); - break; - - case 0x40: - /* STR rd, [rn], -imm */ - arm_access_memory(store, no_op, imm, u32, yes, - offset); - break; - - case 0x41: - /* LDR rd, [rn], -imm */ - arm_access_memory(load, no_op, imm, u32, yes, - offset); - break; - - case 0x42: - /* STRT rd, [rn], -imm */ - arm_access_memory(store, no_op, imm, u32, yes, - offset); - break; - - case 0x43: - /* LDRT rd, [rn], -imm */ - arm_access_memory(load, no_op, imm, u32, yes, - offset); - break; - - case 0x44: - /* STRB rd, [rn], -imm */ - arm_access_memory(store, no_op, imm, u8, yes, - offset); - break; - - case 0x45: - /* LDRB rd, [rn], -imm */ - arm_access_memory(load, no_op, imm, u8, yes, - offset); - break; - - case 0x46: - /* STRBT rd, [rn], -imm */ - arm_access_memory(store, no_op, imm, u8, yes, - offset); - break; - - case 0x47: - /* LDRBT rd, [rn], -imm */ - arm_access_memory(load, no_op, imm, u8, yes, - offset); - break; - - case 0x48: - /* STR rd, [rn], +imm */ - arm_access_memory(store, no_op, imm, u32, yes, + offset); - break; - - case 0x49: - /* LDR rd, [rn], +imm */ - arm_access_memory(load, no_op, imm, u32, yes, + offset); - break; - - case 0x4A: - /* STRT rd, [rn], +imm */ - arm_access_memory(store, no_op, imm, u32, yes, + offset); - break; - - case 0x4B: - /* LDRT rd, [rn], +imm */ - arm_access_memory(load, no_op, imm, u32, yes, + offset); - break; - - case 0x4C: - /* STRB rd, [rn], +imm */ - arm_access_memory(store, no_op, imm, u8, yes, + offset); - break; - - case 0x4D: - /* LDRB rd, [rn], +imm */ - arm_access_memory(load, no_op, imm, u8, yes, + offset); - break; - - case 0x4E: - /* STRBT rd, [rn], +imm */ - arm_access_memory(store, no_op, imm, u8, yes, + offset); - break; - - case 0x4F: - /* LDRBT rd, [rn], +imm */ - arm_access_memory(load, no_op, imm, u8, yes, + offset); - break; - - case 0x50: - /* STR rd, [rn - imm] */ - arm_access_memory(store, - offset, imm, u32, no, no_op); - break; - - case 0x51: - /* LDR rd, [rn - imm] */ - arm_access_memory(load, - offset, imm, u32, no, no_op); - break; - - case 0x52: - /* STR rd, [rn - imm]! */ - arm_access_memory(store, - offset, imm, u32, yes, no_op); - break; - - case 0x53: - /* LDR rd, [rn - imm]! */ - arm_access_memory(load, - offset, imm, u32, yes, no_op); - break; - - case 0x54: - /* STRB rd, [rn - imm] */ - arm_access_memory(store, - offset, imm, u8, no, no_op); - break; - - case 0x55: - /* LDRB rd, [rn - imm] */ - arm_access_memory(load, - offset, imm, u8, no, no_op); - break; - - case 0x56: - /* STRB rd, [rn - imm]! */ - arm_access_memory(store, - offset, imm, u8, yes, no_op); - break; - - case 0x57: - /* LDRB rd, [rn - imm]! */ - arm_access_memory(load, - offset, imm, u8, yes, no_op); - break; - - case 0x58: - /* STR rd, [rn + imm] */ - arm_access_memory(store, + offset, imm, u32, no, no_op); - break; - - case 0x59: - /* LDR rd, [rn + imm] */ - arm_access_memory(load, + offset, imm, u32, no, no_op); - break; - - case 0x5A: - /* STR rd, [rn + imm]! */ - arm_access_memory(store, + offset, imm, u32, yes, no_op); - break; - - case 0x5B: - /* LDR rd, [rn + imm]! */ - arm_access_memory(load, + offset, imm, u32, yes, no_op); - break; - - case 0x5C: - /* STRB rd, [rn + imm] */ - arm_access_memory(store, + offset, imm, u8, no, no_op); - break; - - case 0x5D: - /* LDRB rd, [rn + imm] */ - arm_access_memory(load, + offset, imm, u8, no, no_op); - break; - - case 0x5E: - /* STRB rd, [rn + imm]! */ - arm_access_memory(store, + offset, imm, u8, yes, no_op); - break; - - case 0x5F: - /* LDRBT rd, [rn + imm]! */ - arm_access_memory(load, + offset, imm, u8, yes, no_op); - break; - - case 0x60: - /* STR rd, [rn], -reg_op */ - arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); - break; - - case 0x61: - /* LDR rd, [rn], -reg_op */ - arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); - break; - - case 0x62: - /* STRT rd, [rn], -reg_op */ - arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); - break; - - case 0x63: - /* LDRT rd, [rn], -reg_op */ - arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); - break; - - case 0x64: - /* STRB rd, [rn], -reg_op */ - arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); - break; - - case 0x65: - /* LDRB rd, [rn], -reg_op */ - arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); - break; - - case 0x66: - /* STRBT rd, [rn], -reg_op */ - arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); - break; - - case 0x67: - /* LDRBT rd, [rn], -reg_op */ - arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); - break; - - case 0x68: - /* STR rd, [rn], +reg_op */ - arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); - break; - - case 0x69: - /* LDR rd, [rn], +reg_op */ - arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); - break; - - case 0x6A: - /* STRT rd, [rn], +reg_op */ - arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); - break; - - case 0x6B: - /* LDRT rd, [rn], +reg_op */ - arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); - break; - - case 0x6C: - /* STRB rd, [rn], +reg_op */ - arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); - break; - - case 0x6D: - /* LDRB rd, [rn], +reg_op */ - arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); - break; - - case 0x6E: - /* STRBT rd, [rn], +reg_op */ - arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); - break; - - case 0x6F: - /* LDRBT rd, [rn], +reg_op */ - arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); - break; - - case 0x70: - /* STR rd, [rn - reg_op] */ - arm_access_memory(store, - reg_offset, reg, u32, no, no_op); - break; - - case 0x71: - /* LDR rd, [rn - reg_op] */ - arm_access_memory(load, - reg_offset, reg, u32, no, no_op); - break; - - case 0x72: - /* STR rd, [rn - reg_op]! */ - arm_access_memory(store, - reg_offset, reg, u32, yes, no_op); - break; - - case 0x73: - /* LDR rd, [rn - reg_op]! */ - arm_access_memory(load, - reg_offset, reg, u32, yes, no_op); - break; - - case 0x74: - /* STRB rd, [rn - reg_op] */ - arm_access_memory(store, - reg_offset, reg, u8, no, no_op); - break; - - case 0x75: - /* LDRB rd, [rn - reg_op] */ - arm_access_memory(load, - reg_offset, reg, u8, no, no_op); - break; - - case 0x76: - /* STRB rd, [rn - reg_op]! */ - arm_access_memory(store, - reg_offset, reg, u8, yes, no_op); - break; - - case 0x77: - /* LDRB rd, [rn - reg_op]! */ - arm_access_memory(load, - reg_offset, reg, u8, yes, no_op); - break; - - case 0x78: - /* STR rd, [rn + reg_op] */ - arm_access_memory(store, + reg_offset, reg, u32, no, no_op); - break; - - case 0x79: - /* LDR rd, [rn + reg_op] */ - arm_access_memory(load, + reg_offset, reg, u32, no, no_op); - break; - - case 0x7A: - /* STR rd, [rn + reg_op]! */ - arm_access_memory(store, + reg_offset, reg, u32, yes, no_op); - break; - - case 0x7B: - /* LDR rd, [rn + reg_op]! */ - arm_access_memory(load, + reg_offset, reg, u32, yes, no_op); - break; - - case 0x7C: - /* STRB rd, [rn + reg_op] */ - arm_access_memory(store, + reg_offset, reg, u8, no, no_op); - break; - - case 0x7D: - /* LDRB rd, [rn + reg_op] */ - arm_access_memory(load, + reg_offset, reg, u8, no, no_op); - break; - - case 0x7E: - /* STRB rd, [rn + reg_op]! */ - arm_access_memory(store, + reg_offset, reg, u8, yes, no_op); - break; - - case 0x7F: - /* LDRBT rd, [rn + reg_op]! */ - arm_access_memory(load, + reg_offset, reg, u8, yes, no_op); - break; - - case 0x80: - /* STMDA rn, rlist */ - arm_block_memory(store, down_a, no, no); - break; - - case 0x81: - /* LDMDA rn, rlist */ - arm_block_memory(load, down_a, no, no); - break; - - case 0x82: - /* STMDA rn!, rlist */ - arm_block_memory(store, down_a, down, no); - break; - - case 0x83: - /* LDMDA rn!, rlist */ - arm_block_memory(load, down_a, down, no); - break; - - case 0x84: - /* STMDA rn, rlist^ */ - arm_block_memory(store, down_a, no, yes); - break; - - case 0x85: - /* LDMDA rn, rlist^ */ - arm_block_memory(load, down_a, no, yes); - break; - - case 0x86: - /* STMDA rn!, rlist^ */ - arm_block_memory(store, down_a, down, yes); - break; - - case 0x87: - /* LDMDA rn!, rlist^ */ - arm_block_memory(load, down_a, down, yes); - break; - - case 0x88: - /* STMIA rn, rlist */ - arm_block_memory(store, no, no, no); - break; - - case 0x89: - /* LDMIA rn, rlist */ - arm_block_memory(load, no, no, no); - break; - - case 0x8A: - /* STMIA rn!, rlist */ - arm_block_memory(store, no, up, no); - break; - - case 0x8B: - /* LDMIA rn!, rlist */ - arm_block_memory(load, no, up, no); - break; - - case 0x8C: - /* STMIA rn, rlist^ */ - arm_block_memory(store, no, no, yes); - break; - - case 0x8D: - /* LDMIA rn, rlist^ */ - arm_block_memory(load, no, no, yes); - break; - - case 0x8E: - /* STMIA rn!, rlist^ */ - arm_block_memory(store, no, up, yes); - break; - - case 0x8F: - /* LDMIA rn!, rlist^ */ - arm_block_memory(load, no, up, yes); - break; - - case 0x90: - /* STMDB rn, rlist */ - arm_block_memory(store, down_b, no, no); - break; - - case 0x91: - /* LDMDB rn, rlist */ - arm_block_memory(load, down_b, no, no); - break; - - case 0x92: - /* STMDB rn!, rlist */ - arm_block_memory(store, down_b, down, no); - break; - - case 0x93: - /* LDMDB rn!, rlist */ - arm_block_memory(load, down_b, down, no); - break; - - case 0x94: - /* STMDB rn, rlist^ */ - arm_block_memory(store, down_b, no, yes); - break; - - case 0x95: - /* LDMDB rn, rlist^ */ - arm_block_memory(load, down_b, no, yes); - break; - - case 0x96: - /* STMDB rn!, rlist^ */ - arm_block_memory(store, down_b, down, yes); - break; - - case 0x97: - /* LDMDB rn!, rlist^ */ - arm_block_memory(load, down_b, down, yes); - break; - - case 0x98: - /* STMIB rn, rlist */ - arm_block_memory(store, up, no, no); - break; - - case 0x99: - /* LDMIB rn, rlist */ - arm_block_memory(load, up, no, no); - break; - - case 0x9A: - /* STMIB rn!, rlist */ - arm_block_memory(store, up, up, no); - break; - - case 0x9B: - /* LDMIB rn!, rlist */ - arm_block_memory(load, up, up, no); - break; - - case 0x9C: - /* STMIB rn, rlist^ */ - arm_block_memory(store, up, no, yes); - break; - - case 0x9D: - /* LDMIB rn, rlist^ */ - arm_block_memory(load, up, no, yes); - break; - - case 0x9E: - /* STMIB rn!, rlist^ */ - arm_block_memory(store, up, up, yes); - break; - - case 0x9F: - /* LDMIB rn!, rlist^ */ - arm_block_memory(load, up, up, yes); - break; - - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - { - /* B offset */ - arm_decode_branch(); - arm_pc_offset_update(offset + 8); - break; - } + case 0x4: + /* MI */ + if(!n_flag) + arm_next_instruction(); + break; - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - { - /* BL offset */ - arm_decode_branch(); - reg[REG_LR] = pc + 4; - arm_pc_offset_update(offset + 8); - break; - } + case 0x5: + /* PL */ + if(n_flag) + arm_next_instruction(); + break; -#ifdef HAVE_UNUSED - case 0xC0 ... 0xEF: - /* coprocessor instructions, reserved on GBA */ - break; -#endif + case 0x6: + /* VS */ + if(!v_flag) + arm_next_instruction(); + break; - case 0xF0: - case 0xF1: - case 0xF2: - case 0xF3: - case 0xF4: - case 0xF5: - case 0xF6: - case 0xF7: - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - { - /* SWI comment */ - u32 swi_comment = opcode & 0x00FFFFFF; - - switch(swi_comment >> 16) - { - /* Jump to BIOS SWI handler */ - default: - reg_mode[MODE_SUPERVISOR][6] = pc + 4; - collapse_flags(); - spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; - reg[REG_PC] = 0x00000008; - arm_update_pc(); - reg[REG_CPSR] = (reg[REG_CPSR] & ~0x1F) | 0x13; - set_cpu_mode(MODE_SUPERVISOR); - break; - } - break; - } - } - -skip_instruction: + case 0x7: + /* VC */ + if(v_flag) + arm_next_instruction(); + break; - /* End of Execute ARM instruction */ - cycles_remaining -= cycles_per_instruction; + case 0x8: + /* HI */ + if((c_flag == 0) | z_flag) + arm_next_instruction(); + break; - if (pc == idle_loop_target_pc && cycles_remaining > 0) cycles_remaining = 0; - } while(cycles_remaining > 0); + case 0x9: + /* LS */ + if(c_flag & (z_flag ^ 1)) + arm_next_instruction(); + break; - collapse_flags(); - cycles_remaining = update_gba(); - if (reg[COMPLETED_FRAME]) - return; - continue; + case 0xA: + /* GE */ + if(n_flag != v_flag) + arm_next_instruction(); + break; - do - { -thumb_loop: + case 0xB: + /* LT */ + if(n_flag == v_flag) + arm_next_instruction(); + break; - collapse_flags(); + case 0xC: + /* GT */ + if(z_flag | (n_flag != v_flag)) + arm_next_instruction(); + break; - old_pc = pc; + case 0xD: + /* LE */ + if((z_flag == 0) & (n_flag == v_flag)) + arm_next_instruction(); + break; - /* Execute THUMB instruction */ + case 0xE: + /* AL */ + break; - using_instruction(thumb); - check_pc_region(); - pc &= ~0x01; - opcode = address16(pc_address_block, (pc & 0x7FFF)); + case 0xF: + /* Reserved - treat as "never" */ + arm_next_instruction(); + break; + } - switch((opcode >> 8) & 0xFF) - { + switch((opcode >> 20) & 0xFF) + { case 0x00: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], -rm */ + arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); + } + else + { + /* MUL rd, rm, rs */ + arm_multiply(no_op, no); + } + } + else + { + /* AND rd, rn, reg_op */ + arm_data_proc(reg[rn] & reg_sh, reg); + } + break; + case 0x01: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* MULS rd, rm, rs */ + arm_multiply(no_op, yes); + break; + + case 1: + /* LDRH rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); + break; + + case 2: + /* LDRSB rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); + break; + + case 3: + /* LDRSH rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); + break; + } + } + else + { + /* ANDS rd, rn, reg_op */ + arm_data_proc_logic_flags(reg[rn] & reg_sh, reg); + } + break; + case 0x02: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], -rm */ + arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); + } + else + { + /* MLA rd, rm, rs, rn */ + arm_multiply(+ reg[rn], no); + } + } + else + { + /* EOR rd, rn, reg_op */ + arm_data_proc(reg[rn] ^ reg_sh, reg); + } + break; + case 0x03: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* MLAS rd, rm, rs, rn */ + arm_multiply(+ reg[rn], yes); + break; + + case 1: + /* LDRH rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); + break; + + case 2: + /* LDRSB rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); + break; + + case 3: + /* LDRSH rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); + break; + } + } + else + { + /* EORS rd, rn, reg_op */ + arm_data_proc_logic_flags(reg[rn] ^ reg_sh, reg); + } + break; + case 0x04: + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn], -imm */ + arm_access_memory(store, no_op, half_imm, u16, yes, - offset); + } + else + { + /* SUB rd, rn, reg_op */ + arm_data_proc(reg[rn] - reg_sh, reg); + } + break; + case 0x05: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, u16, yes, - offset); + break; + + case 2: + /* LDRSB rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, s8, yes, - offset); + break; + + case 3: + /* LDRSH rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, s16, yes, - offset); + break; + } + } + else + { + /* SUBS rd, rn, reg_op */ + arm_data_proc_sub_flags(reg[rn], reg_sh, reg); + } + break; + case 0x06: - case 0x07: - /* LSL rd, rs, offset */ - thumb_shift(shift, lsl, imm); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn], -imm */ + arm_access_memory(store, no_op, half_imm, u16, yes, - offset); + } + else + { + /* RSB rd, rn, reg_op */ + arm_data_proc(reg_sh - reg[rn], reg); + } + break; + + case 0x07: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, u16, yes, - offset); + break; + + case 2: + /* LDRSB rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, s8, yes, - offset); + break; + + case 3: + /* LDRSH rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, s16, yes, - offset); + break; + } + } + else + { + /* RSBS rd, rn, reg_op */ + arm_data_proc_sub_flags(reg_sh, reg[rn], reg); + } + break; case 0x08: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], +rm */ + arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); + } + else + { + /* UMULL rd, rm, rs */ + arm_multiply_long(no_op, no, u); + } + } + else + { + /* ADD rd, rn, reg_op */ + arm_data_proc(reg[rn] + reg_sh, reg); + } + break; + case 0x09: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* UMULLS rdlo, rdhi, rm, rs */ + arm_multiply_long(no_op, yes, u); + break; + + case 1: + /* LDRH rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); + break; + + case 2: + /* LDRSB rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); + break; + + case 3: + /* LDRSH rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); + break; + } + } + else + { + /* ADDS rd, rn, reg_op */ + arm_data_proc_add_flags(reg[rn], reg_sh, reg); + } + break; + case 0x0A: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], +rm */ + arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); + } + else + { + /* UMLAL rd, rm, rs */ + arm_multiply_long(arm_multiply_long_addop(u), no, u); + } + } + else + { + /* ADC rd, rn, reg_op */ + arm_data_proc(reg[rn] + reg_sh + c_flag, reg); + } + break; + case 0x0B: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* UMLALS rdlo, rdhi, rm, rs */ + arm_multiply_long(arm_multiply_long_addop(u), yes, u); + break; + + case 1: + /* LDRH rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); + break; + + case 2: + /* LDRSB rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); + break; + + case 3: + /* LDRSH rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); + break; + } + } + else + { + /* ADCS rd, rn, reg_op */ + arm_data_proc_add_flags(reg[rn], reg_sh + c_flag, reg); + } + break; + case 0x0C: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], +imm */ + arm_access_memory(store, no_op, half_imm, u16, yes, + offset); + } + else + { + /* SMULL rd, rm, rs */ + arm_multiply_long(no_op, no, s); + } + } + else + { + /* SBC rd, rn, reg_op */ + arm_data_proc(reg[rn] - (reg_sh + (c_flag ^ 1)), reg); + } + break; + case 0x0D: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* SMULLS rdlo, rdhi, rm, rs */ + arm_multiply_long(no_op, yes, s); + break; + + case 1: + /* LDRH rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, u16, yes, + offset); + break; + + case 2: + /* LDRSB rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, s8, yes, + offset); + break; + + case 3: + /* LDRSH rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, s16, yes, + offset); + break; + } + } + else + { + /* SBCS rd, rn, reg_op */ + arm_data_proc_sub_flags(reg[rn], (reg_sh + (c_flag ^ 1)), reg); + } + break; + case 0x0E: - case 0x0F: - /* LSR rd, rs, offset */ - thumb_shift(shift, lsr, imm); - break; + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], +imm */ + arm_access_memory(store, no_op, half_imm, u16, yes, + offset); + } + else + { + /* SMLAL rd, rm, rs */ + arm_multiply_long(arm_multiply_long_addop(s), no, s); + } + } + else + { + /* RSC rd, rn, reg_op */ + arm_data_proc(reg_sh - reg[rn] + c_flag - 1, reg); + } + break; + + case 0x0F: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* SMLALS rdlo, rdhi, rm, rs */ + arm_multiply_long(arm_multiply_long_addop(s), yes, s); + break; + + case 1: + /* LDRH rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, u16, yes, + offset); + break; + + case 2: + /* LDRSB rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, s8, yes, + offset); + break; + + case 3: + /* LDRSH rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, s16, yes, + offset); + break; + } + } + else + { + /* RSCS rd, rn, reg_op */ + arm_data_proc_sub_flags((reg_sh + c_flag - 1), reg[rn], reg); + } + break; case 0x10: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn - rm] */ + arm_access_memory(store, - reg[rm], half_reg, u16, no, no_op); + } + else + { + /* SWP rd, rm, [rn] */ + arm_swap(u32); + } + } + else + { + /* MRS rd, cpsr */ + arm_psr(reg, read, reg[REG_CPSR]); + } + break; + case 0x11: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn - rm] */ + arm_access_memory(load, - reg[rm], half_reg, u16, no, no_op); + break; + + case 2: + /* LDRSB rd, [rn - rm] */ + arm_access_memory(load, - reg[rm], half_reg, s8, no, no_op); + break; + + case 3: + /* LDRSH rd, [rn - rm] */ + arm_access_memory(load, - reg[rm], half_reg, s16, no, no_op); + break; + } + } + else + { + /* TST rd, rn, reg_op */ + arm_data_proc_test_logic(reg[rn] & reg_sh, reg); + } + break; + case 0x12: + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn - rm]! */ + arm_access_memory(store, - reg[rm], half_reg, u16, yes, no_op); + } + else + { + if(opcode & 0x10) + { + /* BX rn */ + arm_decode_branchx(opcode); + u32 src = reg[rn]; + if(src & 0x01) + { + src -= 1; + arm_pc_offset_update_direct(src); + reg[REG_CPSR] |= 0x20; + goto thumb_loop; + } + else + { + arm_pc_offset_update_direct(src); + } + } + else + { + /* MSR cpsr, rm */ + arm_psr(reg, store, cpsr); + } + } + break; + case 0x13: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn - rm]! */ + arm_access_memory(load, - reg[rm], half_reg, u16, yes, no_op); + break; + + case 2: + /* LDRSB rd, [rn - rm]! */ + arm_access_memory(load, - reg[rm], half_reg, s8, yes, no_op); + break; + + case 3: + /* LDRSH rd, [rn - rm]! */ + arm_access_memory(load, - reg[rm], half_reg, s16, yes, no_op); + break; + } + } + else + { + /* TEQ rd, rn, reg_op */ + arm_data_proc_test_logic(reg[rn] ^ reg_sh, reg); + } + break; + case 0x14: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn - imm] */ + arm_access_memory(store, - offset, half_imm, u16, no, no_op); + } + else + { + /* SWPB rd, rm, [rn] */ + arm_swap(u8); + } + } + else + { + /* MRS rd, spsr */ + arm_psr(reg, read, spsr[reg[CPU_MODE]]); + } + break; + case 0x15: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn - imm] */ + arm_access_memory(load, - offset, half_imm, u16, no, no_op); + break; + + case 2: + /* LDRSB rd, [rn - imm] */ + arm_access_memory(load, - offset, half_imm, s8, no, no_op); + break; + + case 3: + /* LDRSH rd, [rn - imm] */ + arm_access_memory(load, - offset, half_imm, s16, no, no_op); + break; + } + } + else + { + /* CMP rn, reg_op */ + arm_data_proc_test_sub(reg[rn], reg_sh, reg); + } + break; + case 0x16: - case 0x17: - /* ASR rd, rs, offset */ - thumb_shift(shift, asr, imm); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn - imm]! */ + arm_access_memory(store, - offset, half_imm, u16, yes, no_op); + } + else + { + /* MSR spsr, rm */ + arm_psr(reg, store, spsr); + } + break; + + case 0x17: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn - imm]! */ + arm_access_memory(load, - offset, half_imm, u16, yes, no_op); + break; + + case 2: + /* LDRSB rd, [rn - imm]! */ + arm_access_memory(load, - offset, half_imm, s8, yes, no_op); + break; + + case 3: + /* LDRSH rd, [rn - imm]! */ + arm_access_memory(load, - offset, half_imm, s16, yes, no_op); + break; + } + } + else + { + /* CMN rd, rn, reg_op */ + arm_data_proc_test_add(reg[rn], reg_sh, reg); + } + break; case 0x18: - case 0x19: - /* ADD rd, rs, rn */ - thumb_add(add_sub, rd, reg[rs], reg[rn]); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn + rm] */ + arm_access_memory(store, + reg[rm], half_reg, u16, no, no_op); + } + else + { + /* ORR rd, rn, reg_op */ + arm_data_proc(reg[rn] | reg_sh, reg); + } + break; + + case 0x19: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn + rm] */ + arm_access_memory(load, + reg[rm], half_reg, u16, no, no_op); + break; + + case 2: + /* LDRSB rd, [rn + rm] */ + arm_access_memory(load, + reg[rm], half_reg, s8, no, no_op); + break; + + case 3: + /* LDRSH rd, [rn + rm] */ + arm_access_memory(load, + reg[rm], half_reg, s16, no, no_op); + break; + } + } + else + { + /* ORRS rd, rn, reg_op */ + arm_data_proc_logic_flags(reg[rn] | reg_sh, reg); + } + break; case 0x1A: - case 0x1B: - /* SUB rd, rs, rn */ - thumb_sub(add_sub, rd, reg[rs], reg[rn]); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn + rm]! */ + arm_access_memory(store, + reg[rm], half_reg, u16, yes, no_op); + } + else + { + /* MOV rd, reg_op */ + arm_data_proc(reg_sh, reg); + } + break; + + case 0x1B: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn + rm]! */ + arm_access_memory(load, + reg[rm], half_reg, u16, yes, no_op); + break; + + case 2: + /* LDRSB rd, [rn + rm]! */ + arm_access_memory(load, + reg[rm], half_reg, s8, yes, no_op); + break; + + case 3: + /* LDRSH rd, [rn + rm]! */ + arm_access_memory(load, + reg[rm], half_reg, s16, yes, no_op); + break; + } + } + else + { + /* MOVS rd, reg_op */ + arm_data_proc_logic_flags(reg_sh, reg); + } + break; case 0x1C: - case 0x1D: - /* ADD rd, rs, imm */ - thumb_add(add_sub_imm, rd, reg[rs], imm); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn + imm] */ + arm_access_memory(store, + offset, half_imm, u16, no, no_op); + } + else + { + /* BIC rd, rn, reg_op */ + arm_data_proc(reg[rn] & (~reg_sh), reg); + } + break; + + case 0x1D: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn + imm] */ + arm_access_memory(load, + offset, half_imm, u16, no, no_op); + break; + + case 2: + /* LDRSB rd, [rn + imm] */ + arm_access_memory(load, + offset, half_imm, s8, no, no_op); + break; + + case 3: + /* LDRSH rd, [rn + imm] */ + arm_access_memory(load, + offset, half_imm, s16, no, no_op); + break; + } + } + else + { + /* BICS rd, rn, reg_op */ + arm_data_proc_logic_flags(reg[rn] & (~reg_sh), reg); + } + break; case 0x1E: - case 0x1F: - /* SUB rd, rs, imm */ - thumb_sub(add_sub_imm, rd, reg[rs], imm); - break; - - case 0x20: - /* MOV r0, imm */ - thumb_logic(imm, 0, imm); - break; - - case 0x21: - /* MOV r1, imm */ - thumb_logic(imm, 1, imm); - break; - - case 0x22: - /* MOV r2, imm */ - thumb_logic(imm, 2, imm); - break; - - case 0x23: - /* MOV r3, imm */ - thumb_logic(imm, 3, imm); - break; - - case 0x24: - /* MOV r4, imm */ - thumb_logic(imm, 4, imm); - break; - - case 0x25: - /* MOV r5, imm */ - thumb_logic(imm, 5, imm); - break; - - case 0x26: - /* MOV r6, imm */ - thumb_logic(imm, 6, imm); - break; - - case 0x27: - /* MOV r7, imm */ - thumb_logic(imm, 7, imm); - break; - - case 0x28: - /* CMP r0, imm */ - thumb_test_sub(imm, reg[0], imm); - break; - - case 0x29: - /* CMP r1, imm */ - thumb_test_sub(imm, reg[1], imm); - break; - - case 0x2A: - /* CMP r2, imm */ - thumb_test_sub(imm, reg[2], imm); - break; - - case 0x2B: - /* CMP r3, imm */ - thumb_test_sub(imm, reg[3], imm); - break; - - case 0x2C: - /* CMP r4, imm */ - thumb_test_sub(imm, reg[4], imm); - break; - - case 0x2D: - /* CMP r5, imm */ - thumb_test_sub(imm, reg[5], imm); - break; - - case 0x2E: - /* CMP r6, imm */ - thumb_test_sub(imm, reg[6], imm); - break; - - case 0x2F: - /* CMP r7, imm */ - thumb_test_sub(imm, reg[7], imm); - break; - - case 0x30: - /* ADD r0, imm */ - thumb_add(imm, 0, reg[0], imm); - break; - - case 0x31: - /* ADD r1, imm */ - thumb_add(imm, 1, reg[1], imm); - break; - - case 0x32: - /* ADD r2, imm */ - thumb_add(imm, 2, reg[2], imm); - break; - - case 0x33: - /* ADD r3, imm */ - thumb_add(imm, 3, reg[3], imm); - break; - - case 0x34: - /* ADD r4, imm */ - thumb_add(imm, 4, reg[4], imm); - break; - - case 0x35: - /* ADD r5, imm */ - thumb_add(imm, 5, reg[5], imm); - break; - - case 0x36: - /* ADD r6, imm */ - thumb_add(imm, 6, reg[6], imm); - break; - - case 0x37: - /* ADD r7, imm */ - thumb_add(imm, 7, reg[7], imm); - break; - - case 0x38: - /* SUB r0, imm */ - thumb_sub(imm, 0, reg[0], imm); - break; - - case 0x39: - /* SUB r1, imm */ - thumb_sub(imm, 1, reg[1], imm); - break; - - case 0x3A: - /* SUB r2, imm */ - thumb_sub(imm, 2, reg[2], imm); - break; - - case 0x3B: - /* SUB r3, imm */ - thumb_sub(imm, 3, reg[3], imm); - break; - - case 0x3C: - /* SUB r4, imm */ - thumb_sub(imm, 4, reg[4], imm); - break; - - case 0x3D: - /* SUB r5, imm */ - thumb_sub(imm, 5, reg[5], imm); - break; - - case 0x3E: - /* SUB r6, imm */ - thumb_sub(imm, 6, reg[6], imm); - break; - - case 0x3F: - /* SUB r7, imm */ - thumb_sub(imm, 7, reg[7], imm); - break; - - case 0x40: - switch((opcode >> 6) & 0x03) - { - case 0x00: - /* AND rd, rs */ - thumb_logic(alu_op, rd, reg[rd] & reg[rs]); - break; - - case 0x01: - /* EOR rd, rs */ - thumb_logic(alu_op, rd, reg[rd] ^ reg[rs]); - break; - - case 0x02: - /* LSL rd, rs */ - thumb_shift(alu_op, lsl, reg); - break; - - case 0x03: - /* LSR rd, rs */ - thumb_shift(alu_op, lsr, reg); - break; - } - break; - - case 0x41: - switch((opcode >> 6) & 0x03) - { - case 0x00: - /* ASR rd, rs */ - thumb_shift(alu_op, asr, reg); - break; - - case 0x01: - /* ADC rd, rs */ - thumb_add(alu_op, rd, reg[rd] + reg[rs], c_flag); - break; - - case 0x02: - /* SBC rd, rs */ - thumb_sub(alu_op, rd, reg[rd] - reg[rs], (c_flag ^ 1)); - break; - - case 0x03: - /* ROR rd, rs */ - thumb_shift(alu_op, ror, reg); - break; - } - break; - - case 0x42: - switch((opcode >> 6) & 0x03) - { - case 0x00: - /* TST rd, rs */ - thumb_test_logic(alu_op, reg[rd] & reg[rs]); - break; - - case 0x01: - /* NEG rd, rs */ - thumb_sub(alu_op, rd, 0, reg[rs]); - break; - - case 0x02: - /* CMP rd, rs */ - thumb_test_sub(alu_op, reg[rd], reg[rs]); - break; - - case 0x03: - /* CMN rd, rs */ - thumb_test_add(alu_op, reg[rd], reg[rs]); - break; - } - break; - - case 0x43: - switch((opcode >> 6) & 0x03) - { - case 0x00: - /* ORR rd, rs */ - thumb_logic(alu_op, rd, reg[rd] | reg[rs]); - break; - - case 0x01: - /* MUL rd, rs */ - thumb_logic(alu_op, rd, reg[rd] * reg[rs]); - break; - - case 0x02: - /* BIC rd, rs */ - thumb_logic(alu_op, rd, reg[rd] & (~reg[rs])); - break; - - case 0x03: - /* MVN rd, rs */ - thumb_logic(alu_op, rd, ~reg[rs]); - break; - } - break; - - case 0x44: - /* ADD rd, rs */ - thumb_hireg_op(reg[rd] + reg[rs]); - break; - - case 0x45: - /* CMP rd, rs */ - { - thumb_pc_offset(4); - thumb_decode_hireg_op(); - u32 _sa = reg[rd]; - u32 _sb = reg[rs]; - u32 dest = _sa - _sb; - thumb_pc_offset(-2); - calculate_flags_sub(dest, _sa, _sb); - } - break; - - case 0x46: - /* MOV rd, rs */ - thumb_hireg_op(reg[rs]); - break; - - case 0x47: - /* BX rs */ - { - thumb_decode_hireg_op(); - u32 src; - thumb_pc_offset(4); - src = reg[rs]; - if(src & 0x01) - { - src -= 1; - thumb_pc_offset_update_direct(src); - } - else - { - /* Switch to ARM mode */ - thumb_pc_offset_update_direct(src); - reg[REG_CPSR] &= ~0x20; - collapse_flags(); - goto arm_loop; - } - } - break; - - case 0x48: - /* LDR r0, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[0], u32); - break; - - case 0x49: - /* LDR r1, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[1], u32); - break; - - case 0x4A: - /* LDR r2, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[2], u32); - break; - - case 0x4B: - /* LDR r3, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[3], u32); - break; - - case 0x4C: - /* LDR r4, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[4], u32); - break; - - case 0x4D: - /* LDR r5, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[5], u32); - break; - - case 0x4E: - /* LDR r6, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[6], u32); - break; - - case 0x4F: - /* LDR r7, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[7], u32); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn + imm]! */ + arm_access_memory(store, + offset, half_imm, u16, yes, no_op); + } + else + { + /* MVN rd, reg_op */ + arm_data_proc(~reg_sh, reg); + } + break; + + case 0x1F: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn + imm]! */ + arm_access_memory(load, + offset, half_imm, u16, yes, no_op); + break; + + case 2: + /* LDRSB rd, [rn + imm]! */ + arm_access_memory(load, + offset, half_imm, s8, yes, no_op); + break; + + case 3: + /* LDRSH rd, [rn + imm]! */ + arm_access_memory(load, + offset, half_imm, s16, yes, no_op); + break; + } + } + else + { + /* MVNS rd, rn, reg_op */ + arm_data_proc_logic_flags(~reg_sh, reg); + } + break; + + case 0x20: + /* AND rd, rn, imm */ + arm_data_proc(reg[rn] & imm, imm); + break; + + case 0x21: + /* ANDS rd, rn, imm */ + arm_data_proc_logic_flags(reg[rn] & imm, imm); + break; + + case 0x22: + /* EOR rd, rn, imm */ + arm_data_proc(reg[rn] ^ imm, imm); + break; + + case 0x23: + /* EORS rd, rn, imm */ + arm_data_proc_logic_flags(reg[rn] ^ imm, imm); + break; + + case 0x24: + /* SUB rd, rn, imm */ + arm_data_proc(reg[rn] - imm, imm); + break; + + case 0x25: + /* SUBS rd, rn, imm */ + arm_data_proc_sub_flags(reg[rn], imm, imm); + break; + + case 0x26: + /* RSB rd, rn, imm */ + arm_data_proc(imm - reg[rn], imm); + break; + + case 0x27: + /* RSBS rd, rn, imm */ + arm_data_proc_sub_flags(imm, reg[rn], imm); + break; + + case 0x28: + /* ADD rd, rn, imm */ + arm_data_proc(reg[rn] + imm, imm); + break; + + case 0x29: + /* ADDS rd, rn, imm */ + arm_data_proc_add_flags(reg[rn], imm, imm); + break; + + case 0x2A: + /* ADC rd, rn, imm */ + arm_data_proc(reg[rn] + imm + c_flag, imm); + break; + + case 0x2B: + /* ADCS rd, rn, imm */ + arm_data_proc_add_flags(reg[rn] + imm, c_flag, imm); + break; + + case 0x2C: + /* SBC rd, rn, imm */ + arm_data_proc(reg[rn] - imm + c_flag - 1, imm); + break; + + case 0x2D: + /* SBCS rd, rn, imm */ + arm_data_proc_sub_flags(reg[rn], (imm + (c_flag ^ 1)), imm); + break; + + case 0x2E: + /* RSC rd, rn, imm */ + arm_data_proc(imm - reg[rn] + c_flag - 1, imm); + break; + + case 0x2F: + /* RSCS rd, rn, imm */ + arm_data_proc_sub_flags((imm + c_flag - 1), reg[rn], imm); + break; + + case 0x30: + case 0x31: + /* TST rn, imm */ + arm_data_proc_test_logic(reg[rn] & imm, imm); + break; + + case 0x32: + /* MSR cpsr, imm */ + arm_psr(imm, store, cpsr); + break; + + case 0x33: + /* TEQ rn, imm */ + arm_data_proc_test_logic(reg[rn] ^ imm, imm); + break; + + case 0x34: + case 0x35: + /* CMP rn, imm */ + arm_data_proc_test_sub(reg[rn], imm, imm); + break; + + case 0x36: + /* MSR spsr, imm */ + arm_psr(imm, store, spsr); + break; + + case 0x37: + /* CMN rn, imm */ + arm_data_proc_test_add(reg[rn], imm, imm); + break; + + case 0x38: + /* ORR rd, rn, imm */ + arm_data_proc(reg[rn] | imm, imm); + break; + + case 0x39: + /* ORRS rd, rn, imm */ + arm_data_proc_logic_flags(reg[rn] | imm, imm); + break; + + case 0x3A: + /* MOV rd, imm */ + arm_data_proc(imm, imm); + break; + + case 0x3B: + /* MOVS rd, imm */ + arm_data_proc_logic_flags(imm, imm); + break; + + case 0x3C: + /* BIC rd, rn, imm */ + arm_data_proc(reg[rn] & (~imm), imm); + break; + + case 0x3D: + /* BICS rd, rn, imm */ + arm_data_proc_logic_flags(reg[rn] & (~imm), imm); + break; + + case 0x3E: + /* MVN rd, imm */ + arm_data_proc(~imm, imm); + break; + + case 0x3F: + /* MVNS rd, imm */ + arm_data_proc_logic_flags(~imm, imm); + break; + + case 0x40: + /* STR rd, [rn], -imm */ + arm_access_memory(store, no_op, imm, u32, yes, - offset); + break; + + case 0x41: + /* LDR rd, [rn], -imm */ + arm_access_memory(load, no_op, imm, u32, yes, - offset); + break; + + case 0x42: + /* STRT rd, [rn], -imm */ + arm_access_memory(store, no_op, imm, u32, yes, - offset); + break; + + case 0x43: + /* LDRT rd, [rn], -imm */ + arm_access_memory(load, no_op, imm, u32, yes, - offset); + break; + + case 0x44: + /* STRB rd, [rn], -imm */ + arm_access_memory(store, no_op, imm, u8, yes, - offset); + break; + + case 0x45: + /* LDRB rd, [rn], -imm */ + arm_access_memory(load, no_op, imm, u8, yes, - offset); + break; + + case 0x46: + /* STRBT rd, [rn], -imm */ + arm_access_memory(store, no_op, imm, u8, yes, - offset); + break; + + case 0x47: + /* LDRBT rd, [rn], -imm */ + arm_access_memory(load, no_op, imm, u8, yes, - offset); + break; + + case 0x48: + /* STR rd, [rn], +imm */ + arm_access_memory(store, no_op, imm, u32, yes, + offset); + break; + + case 0x49: + /* LDR rd, [rn], +imm */ + arm_access_memory(load, no_op, imm, u32, yes, + offset); + break; + + case 0x4A: + /* STRT rd, [rn], +imm */ + arm_access_memory(store, no_op, imm, u32, yes, + offset); + break; + + case 0x4B: + /* LDRT rd, [rn], +imm */ + arm_access_memory(load, no_op, imm, u32, yes, + offset); + break; + + case 0x4C: + /* STRB rd, [rn], +imm */ + arm_access_memory(store, no_op, imm, u8, yes, + offset); + break; + + case 0x4D: + /* LDRB rd, [rn], +imm */ + arm_access_memory(load, no_op, imm, u8, yes, + offset); + break; + + case 0x4E: + /* STRBT rd, [rn], +imm */ + arm_access_memory(store, no_op, imm, u8, yes, + offset); + break; + + case 0x4F: + /* LDRBT rd, [rn], +imm */ + arm_access_memory(load, no_op, imm, u8, yes, + offset); + break; case 0x50: - case 0x51: - /* STR rd, [rb + ro] */ - thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u32); - break; + /* STR rd, [rn - imm] */ + arm_access_memory(store, - offset, imm, u32, no, no_op); + break; + + case 0x51: + /* LDR rd, [rn - imm] */ + arm_access_memory(load, - offset, imm, u32, no, no_op); + break; case 0x52: - case 0x53: - /* STRH rd, [rb + ro] */ - thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u16); - break; + /* STR rd, [rn - imm]! */ + arm_access_memory(store, - offset, imm, u32, yes, no_op); + break; + + case 0x53: + /* LDR rd, [rn - imm]! */ + arm_access_memory(load, - offset, imm, u32, yes, no_op); + break; case 0x54: + /* STRB rd, [rn - imm] */ + arm_access_memory(store, - offset, imm, u8, no, no_op); + break; + case 0x55: - /* STRB rd, [rb + ro] */ - thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u8); - break; + /* LDRB rd, [rn - imm] */ + arm_access_memory(load, - offset, imm, u8, no, no_op); + break; case 0x56: + /* STRB rd, [rn - imm]! */ + arm_access_memory(store, - offset, imm, u8, yes, no_op); + break; + case 0x57: - /* LDSB rd, [rb + ro] */ - thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], s8); - break; + /* LDRB rd, [rn - imm]! */ + arm_access_memory(load, - offset, imm, u8, yes, no_op); + break; case 0x58: + /* STR rd, [rn + imm] */ + arm_access_memory(store, + offset, imm, u32, no, no_op); + break; + case 0x59: - /* LDR rd, [rb + ro] */ - thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u32); - break; + /* LDR rd, [rn + imm] */ + arm_access_memory(load, + offset, imm, u32, no, no_op); + break; case 0x5A: + /* STR rd, [rn + imm]! */ + arm_access_memory(store, + offset, imm, u32, yes, no_op); + break; + case 0x5B: - /* LDRH rd, [rb + ro] */ - thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u16); - break; + /* LDR rd, [rn + imm]! */ + arm_access_memory(load, + offset, imm, u32, yes, no_op); + break; case 0x5C: + /* STRB rd, [rn + imm] */ + arm_access_memory(store, + offset, imm, u8, no, no_op); + break; + case 0x5D: - /* LDRB rd, [rb + ro] */ - thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u8); - break; + /* LDRB rd, [rn + imm] */ + arm_access_memory(load, + offset, imm, u8, no, no_op); + break; case 0x5E: + /* STRB rd, [rn + imm]! */ + arm_access_memory(store, + offset, imm, u8, yes, no_op); + break; + case 0x5F: - /* LDSH rd, [rb + ro] */ - thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], s16); - break; + /* LDRBT rd, [rn + imm]! */ + arm_access_memory(load, + offset, imm, u8, yes, no_op); + break; case 0x60: + /* STR rd, [rn], -reg_op */ + arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); + break; + case 0x61: + /* LDR rd, [rn], -reg_op */ + arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); + break; + case 0x62: + /* STRT rd, [rn], -reg_op */ + arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); + break; + case 0x63: + /* LDRT rd, [rn], -reg_op */ + arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); + break; + case 0x64: + /* STRB rd, [rn], -reg_op */ + arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); + break; + case 0x65: + /* LDRB rd, [rn], -reg_op */ + arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); + break; + case 0x66: - case 0x67: - /* STR rd, [rb + imm] */ - thumb_access_memory(store, mem_imm, reg[rb] + (imm * 4), reg[rd], u32); - break; + /* STRBT rd, [rn], -reg_op */ + arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); + break; + + case 0x67: + /* LDRBT rd, [rn], -reg_op */ + arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); + break; case 0x68: + /* STR rd, [rn], +reg_op */ + arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); + break; + case 0x69: + /* LDR rd, [rn], +reg_op */ + arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); + break; + case 0x6A: + /* STRT rd, [rn], +reg_op */ + arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); + break; + case 0x6B: + /* LDRT rd, [rn], +reg_op */ + arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); + break; + case 0x6C: + /* STRB rd, [rn], +reg_op */ + arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); + break; + case 0x6D: + /* LDRB rd, [rn], +reg_op */ + arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); + break; + case 0x6E: - case 0x6F: - /* LDR rd, [rb + imm] */ - thumb_access_memory(load, mem_imm, reg[rb] + (imm * 4), reg[rd], u32); - break; + /* STRBT rd, [rn], +reg_op */ + arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); + break; + + case 0x6F: + /* LDRBT rd, [rn], +reg_op */ + arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); + break; case 0x70: + /* STR rd, [rn - reg_op] */ + arm_access_memory(store, - reg_offset, reg, u32, no, no_op); + break; + case 0x71: + /* LDR rd, [rn - reg_op] */ + arm_access_memory(load, - reg_offset, reg, u32, no, no_op); + break; + case 0x72: + /* STR rd, [rn - reg_op]! */ + arm_access_memory(store, - reg_offset, reg, u32, yes, no_op); + break; + case 0x73: + /* LDR rd, [rn - reg_op]! */ + arm_access_memory(load, - reg_offset, reg, u32, yes, no_op); + break; + case 0x74: + /* STRB rd, [rn - reg_op] */ + arm_access_memory(store, - reg_offset, reg, u8, no, no_op); + break; + case 0x75: + /* LDRB rd, [rn - reg_op] */ + arm_access_memory(load, - reg_offset, reg, u8, no, no_op); + break; + case 0x76: - case 0x77: - /* STRB rd, [rb + imm] */ - thumb_access_memory(store, mem_imm, reg[rb] + imm, reg[rd], u8); - break; + /* STRB rd, [rn - reg_op]! */ + arm_access_memory(store, - reg_offset, reg, u8, yes, no_op); + break; + + case 0x77: + /* LDRB rd, [rn - reg_op]! */ + arm_access_memory(load, - reg_offset, reg, u8, yes, no_op); + break; case 0x78: + /* STR rd, [rn + reg_op] */ + arm_access_memory(store, + reg_offset, reg, u32, no, no_op); + break; + case 0x79: + /* LDR rd, [rn + reg_op] */ + arm_access_memory(load, + reg_offset, reg, u32, no, no_op); + break; + case 0x7A: + /* STR rd, [rn + reg_op]! */ + arm_access_memory(store, + reg_offset, reg, u32, yes, no_op); + break; + case 0x7B: + /* LDR rd, [rn + reg_op]! */ + arm_access_memory(load, + reg_offset, reg, u32, yes, no_op); + break; + case 0x7C: + /* STRB rd, [rn + reg_op] */ + arm_access_memory(store, + reg_offset, reg, u8, no, no_op); + break; + case 0x7D: + /* LDRB rd, [rn + reg_op] */ + arm_access_memory(load, + reg_offset, reg, u8, no, no_op); + break; + case 0x7E: - case 0x7F: - /* LDRB rd, [rb + imm] */ - thumb_access_memory(load, mem_imm, reg[rb] + imm, reg[rd], u8); - break; + /* STRB rd, [rn + reg_op]! */ + arm_access_memory(store, + reg_offset, reg, u8, yes, no_op); + break; + + case 0x7F: + /* LDRBT rd, [rn + reg_op]! */ + arm_access_memory(load, + reg_offset, reg, u8, yes, no_op); + break; case 0x80: + /* STMDA rn, rlist */ + arm_block_memory(store, down_a, no, no); + break; + case 0x81: + /* LDMDA rn, rlist */ + arm_block_memory(load, down_a, no, no); + break; + case 0x82: + /* STMDA rn!, rlist */ + arm_block_memory(store, down_a, down, no); + break; + case 0x83: + /* LDMDA rn!, rlist */ + arm_block_memory(load, down_a, down, no); + break; + case 0x84: + /* STMDA rn, rlist^ */ + arm_block_memory(store, down_a, no, yes); + break; + case 0x85: + /* LDMDA rn, rlist^ */ + arm_block_memory(load, down_a, no, yes); + break; + case 0x86: - case 0x87: - /* STRH rd, [rb + imm] */ - thumb_access_memory(store, mem_imm, reg[rb] + (imm * 2), reg[rd], u16); - break; + /* STMDA rn!, rlist^ */ + arm_block_memory(store, down_a, down, yes); + break; + + case 0x87: + /* LDMDA rn!, rlist^ */ + arm_block_memory(load, down_a, down, yes); + break; case 0x88: + /* STMIA rn, rlist */ + arm_block_memory(store, no, no, no); + break; + case 0x89: + /* LDMIA rn, rlist */ + arm_block_memory(load, no, no, no); + break; + case 0x8A: + /* STMIA rn!, rlist */ + arm_block_memory(store, no, up, no); + break; + case 0x8B: + /* LDMIA rn!, rlist */ + arm_block_memory(load, no, up, no); + break; + case 0x8C: + /* STMIA rn, rlist^ */ + arm_block_memory(store, no, no, yes); + break; + case 0x8D: + /* LDMIA rn, rlist^ */ + arm_block_memory(load, no, no, yes); + break; + case 0x8E: - case 0x8F: - /* LDRH rd, [rb + imm] */ - thumb_access_memory(load, mem_imm, reg[rb] + (imm * 2), reg[rd], u16); - break; - - case 0x90: - /* STR r0, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[0], u32); - break; - - case 0x91: - /* STR r1, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[1], u32); - break; - - case 0x92: - /* STR r2, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[2], u32); - break; - - case 0x93: - /* STR r3, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[3], u32); - break; - - case 0x94: - /* STR r4, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[4], u32); - break; - - case 0x95: - /* STR r5, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[5], u32); - break; - - case 0x96: - /* STR r6, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[6], u32); - break; - - case 0x97: - /* STR r7, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[7], u32); - break; - - case 0x98: - /* LDR r0, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[0], u32); - break; - - case 0x99: - /* LDR r1, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[1], u32); - break; - - case 0x9A: - /* LDR r2, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[2], u32); - break; - - case 0x9B: - /* LDR r3, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[3], u32); - break; - - case 0x9C: - /* LDR r4, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[4], u32); - break; - - case 0x9D: - /* LDR r5, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[5], u32); - break; - - case 0x9E: - /* LDR r6, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[6], u32); - break; - - case 0x9F: - /* LDR r7, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[7], u32); - break; - - case 0xA0: - /* ADD r0, pc, +imm */ - thumb_add_noflags(imm, 0, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA1: - /* ADD r1, pc, +imm */ - thumb_add_noflags(imm, 1, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA2: - /* ADD r2, pc, +imm */ - thumb_add_noflags(imm, 2, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA3: - /* ADD r3, pc, +imm */ - thumb_add_noflags(imm, 3, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA4: - /* ADD r4, pc, +imm */ - thumb_add_noflags(imm, 4, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA5: - /* ADD r5, pc, +imm */ - thumb_add_noflags(imm, 5, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA6: - /* ADD r6, pc, +imm */ - thumb_add_noflags(imm, 6, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA7: - /* ADD r7, pc, +imm */ - thumb_add_noflags(imm, 7, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA8: - /* ADD r0, sp, +imm */ - thumb_add_noflags(imm, 0, reg[REG_SP], (imm * 4)); - break; - - case 0xA9: - /* ADD r1, sp, +imm */ - thumb_add_noflags(imm, 1, reg[REG_SP], (imm * 4)); - break; - - case 0xAA: - /* ADD r2, sp, +imm */ - thumb_add_noflags(imm, 2, reg[REG_SP], (imm * 4)); - break; - - case 0xAB: - /* ADD r3, sp, +imm */ - thumb_add_noflags(imm, 3, reg[REG_SP], (imm * 4)); - break; - - case 0xAC: - /* ADD r4, sp, +imm */ - thumb_add_noflags(imm, 4, reg[REG_SP], (imm * 4)); - break; - - case 0xAD: - /* ADD r5, sp, +imm */ - thumb_add_noflags(imm, 5, reg[REG_SP], (imm * 4)); - break; - - case 0xAE: - /* ADD r6, sp, +imm */ - thumb_add_noflags(imm, 6, reg[REG_SP], (imm * 4)); - break; - - case 0xAF: - /* ADD r7, sp, +imm */ - thumb_add_noflags(imm, 7, reg[REG_SP], (imm * 4)); - break; + /* STMIA rn!, rlist^ */ + arm_block_memory(store, no, up, yes); + break; + + case 0x8F: + /* LDMIA rn!, rlist^ */ + arm_block_memory(load, no, up, yes); + break; + + case 0x90: + /* STMDB rn, rlist */ + arm_block_memory(store, down_b, no, no); + break; + + case 0x91: + /* LDMDB rn, rlist */ + arm_block_memory(load, down_b, no, no); + break; + + case 0x92: + /* STMDB rn!, rlist */ + arm_block_memory(store, down_b, down, no); + break; + + case 0x93: + /* LDMDB rn!, rlist */ + arm_block_memory(load, down_b, down, no); + break; + + case 0x94: + /* STMDB rn, rlist^ */ + arm_block_memory(store, down_b, no, yes); + break; + + case 0x95: + /* LDMDB rn, rlist^ */ + arm_block_memory(load, down_b, no, yes); + break; + + case 0x96: + /* STMDB rn!, rlist^ */ + arm_block_memory(store, down_b, down, yes); + break; + + case 0x97: + /* LDMDB rn!, rlist^ */ + arm_block_memory(load, down_b, down, yes); + break; + + case 0x98: + /* STMIB rn, rlist */ + arm_block_memory(store, up, no, no); + break; + + case 0x99: + /* LDMIB rn, rlist */ + arm_block_memory(load, up, no, no); + break; + + case 0x9A: + /* STMIB rn!, rlist */ + arm_block_memory(store, up, up, no); + break; + + case 0x9B: + /* LDMIB rn!, rlist */ + arm_block_memory(load, up, up, no); + break; + + case 0x9C: + /* STMIB rn, rlist^ */ + arm_block_memory(store, up, no, yes); + break; + + case 0x9D: + /* LDMIB rn, rlist^ */ + arm_block_memory(load, up, no, yes); + break; + + case 0x9E: + /* STMIB rn!, rlist^ */ + arm_block_memory(store, up, up, yes); + break; + + case 0x9F: + /* LDMIB rn!, rlist^ */ + arm_block_memory(load, up, up, yes); + break; + + case 0xA0 ... 0xAF: + { + /* B offset */ + arm_decode_branch(); + arm_pc_offset_update(offset + 8); + break; + } + + case 0xB0 ... 0xBF: + { + /* BL offset */ + arm_decode_branch(); + reg[REG_LR] = pc + 4; + arm_pc_offset_update(offset + 8); + break; + } + +#ifdef HAVE_UNUSED + case 0xC0 ... 0xEF: + /* coprocessor instructions, reserved on GBA */ + break; +#endif + + case 0xF0 ... 0xFF: + { + /* SWI comment */ + u32 swi_comment = opcode & 0x00FFFFFF; + + switch(swi_comment >> 16) + { + /* Jump to BIOS SWI handler */ + default: + reg_mode[MODE_SUPERVISOR][6] = pc + 4; + collapse_flags(); + spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; + reg[REG_PC] = 0x00000008; + arm_update_pc(); + reg[REG_CPSR] = (reg[REG_CPSR] & ~0x1F) | 0x13; + set_cpu_mode(MODE_SUPERVISOR); + break; + } + break; + } + } + +skip_instruction: + + /* End of Execute ARM instruction */ + cycles_remaining -= cycles_per_instruction; + + if (pc == idle_loop_target_pc && cycles_remaining > 0) cycles_remaining = 0; + } while(cycles_remaining > 0); + + collapse_flags(); + cycles_remaining = update_gba(); + if (reg[COMPLETED_FRAME]) + return; + continue; + + do + { +thumb_loop: + + collapse_flags(); + + /* Process cheats if we are about to execute the cheat hook */ + if (pc == cheat_master_hook) + process_cheats(); + + old_pc = pc; + + /* Execute THUMB instruction */ + + using_instruction(thumb); + check_pc_region(); + pc &= ~0x01; + opcode = readaddress16(pc_address_block, (pc & 0x7FFF)); + + switch((opcode >> 8) & 0xFF) + { + case 0x00 ... 0x07: + /* LSL rd, rs, offset */ + thumb_shift(shift, lsl, imm); + break; + + case 0x08 ... 0x0F: + /* LSR rd, rs, offset */ + thumb_shift(shift, lsr, imm); + break; + + case 0x10 ... 0x17: + /* ASR rd, rs, offset */ + thumb_shift(shift, asr, imm); + break; + + case 0x18: + case 0x19: + /* ADD rd, rs, rn */ + thumb_add(add_sub, rd, reg[rs], reg[rn]); + break; + + case 0x1A: + case 0x1B: + /* SUB rd, rs, rn */ + thumb_sub(add_sub, rd, reg[rs], reg[rn]); + break; + + case 0x1C: + case 0x1D: + /* ADD rd, rs, imm */ + thumb_add(add_sub_imm, rd, reg[rs], imm); + break; + + case 0x1E: + case 0x1F: + /* SUB rd, rs, imm */ + thumb_sub(add_sub_imm, rd, reg[rs], imm); + break; + + case 0x20 ... 0x27: + /* MOV r0..7, imm */ + thumb_logic(imm, ((opcode >> 8) & 7), imm); + break; + + case 0x28 ... 0x2F: + /* CMP r0..7, imm */ + thumb_test_sub(imm, reg[(opcode >> 8) & 7], imm); + break; + + case 0x30 ... 0x37: + /* ADD r0..7, imm */ + thumb_add(imm, ((opcode >> 8) & 7), reg[(opcode >> 8) & 7], imm); + break; + + case 0x38 ... 0x3F: + /* SUB r0..7, imm */ + thumb_sub(imm, ((opcode >> 8) & 7), reg[(opcode >> 8) & 7], imm); + break; + + case 0x40: + switch((opcode >> 6) & 0x03) + { + case 0x00: + /* AND rd, rs */ + thumb_logic(alu_op, rd, reg[rd] & reg[rs]); + break; + + case 0x01: + /* EOR rd, rs */ + thumb_logic(alu_op, rd, reg[rd] ^ reg[rs]); + break; + + case 0x02: + /* LSL rd, rs */ + thumb_shift(alu_op, lsl, reg); + break; + + case 0x03: + /* LSR rd, rs */ + thumb_shift(alu_op, lsr, reg); + break; + } + break; + + case 0x41: + switch((opcode >> 6) & 0x03) + { + case 0x00: + /* ASR rd, rs */ + thumb_shift(alu_op, asr, reg); + break; + + case 0x01: + /* ADC rd, rs */ + thumb_add(alu_op, rd, reg[rd] + reg[rs], c_flag); + break; + + case 0x02: + /* SBC rd, rs */ + thumb_sub(alu_op, rd, reg[rd] - reg[rs], (c_flag ^ 1)); + break; + + case 0x03: + /* ROR rd, rs */ + thumb_shift(alu_op, ror, reg); + break; + } + break; + + case 0x42: + switch((opcode >> 6) & 0x03) + { + case 0x00: + /* TST rd, rs */ + thumb_test_logic(alu_op, reg[rd] & reg[rs]); + break; + + case 0x01: + /* NEG rd, rs */ + thumb_sub(alu_op, rd, 0, reg[rs]); + break; + + case 0x02: + /* CMP rd, rs */ + thumb_test_sub(alu_op, reg[rd], reg[rs]); + break; + + case 0x03: + /* CMN rd, rs */ + thumb_test_add(alu_op, reg[rd], reg[rs]); + break; + } + break; + + case 0x43: + switch((opcode >> 6) & 0x03) + { + case 0x00: + /* ORR rd, rs */ + thumb_logic(alu_op, rd, reg[rd] | reg[rs]); + break; + + case 0x01: + /* MUL rd, rs */ + thumb_logic(alu_op, rd, reg[rd] * reg[rs]); + break; + + case 0x02: + /* BIC rd, rs */ + thumb_logic(alu_op, rd, reg[rd] & (~reg[rs])); + break; + + case 0x03: + /* MVN rd, rs */ + thumb_logic(alu_op, rd, ~reg[rs]); + break; + } + break; + + case 0x44: + /* ADD rd, rs */ + thumb_hireg_op(reg[rd] + reg[rs]); + break; + + case 0x45: + /* CMP rd, rs */ + { + thumb_pc_offset(4); + thumb_decode_hireg_op(); + u32 _sa = reg[rd]; + u32 _sb = reg[rs]; + u32 dest = _sa - _sb; + thumb_pc_offset(-2); + calculate_flags_sub(dest, _sa, _sb); + } + break; + + case 0x46: + /* MOV rd, rs */ + thumb_hireg_op(reg[rs]); + break; + + case 0x47: + /* BX rs */ + { + thumb_decode_hireg_op(); + u32 src; + thumb_pc_offset(4); + src = reg[rs]; + if(src & 0x01) + { + src -= 1; + thumb_pc_offset_update_direct(src); + } + else + { + /* Switch to ARM mode */ + thumb_pc_offset_update_direct(src); + reg[REG_CPSR] &= ~0x20; + collapse_flags(); + goto arm_loop; + } + } + break; + + case 0x48 ... 0x4F: + /* LDR r0..7, [pc + imm] */ + thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[(opcode >> 8) & 7], u32); + break; + + case 0x50: + case 0x51: + /* STR rd, [rb + ro] */ + thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u32); + break; + + case 0x52: + case 0x53: + /* STRH rd, [rb + ro] */ + thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u16); + break; + + case 0x54: + case 0x55: + /* STRB rd, [rb + ro] */ + thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u8); + break; + + case 0x56: + case 0x57: + /* LDSB rd, [rb + ro] */ + thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], s8); + break; + + case 0x58: + case 0x59: + /* LDR rd, [rb + ro] */ + thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u32); + break; + + case 0x5A: + case 0x5B: + /* LDRH rd, [rb + ro] */ + thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u16); + break; + + case 0x5C: + case 0x5D: + /* LDRB rd, [rb + ro] */ + thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u8); + break; + + case 0x5E: + case 0x5F: + /* LDSH rd, [rb + ro] */ + thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], s16); + break; + + case 0x60 ... 0x67: + /* STR rd, [rb + imm] */ + thumb_access_memory(store, mem_imm, reg[rb] + (imm * 4), reg[rd], u32); + break; + + case 0x68 ... 0x6F: + /* LDR rd, [rb + imm] */ + thumb_access_memory(load, mem_imm, reg[rb] + (imm * 4), reg[rd], u32); + break; + + case 0x70 ... 0x77: + /* STRB rd, [rb + imm] */ + thumb_access_memory(store, mem_imm, reg[rb] + imm, reg[rd], u8); + break; + + case 0x78 ... 0x7F: + /* LDRB rd, [rb + imm] */ + thumb_access_memory(load, mem_imm, reg[rb] + imm, reg[rd], u8); + break; + + case 0x80 ... 0x87: + /* STRH rd, [rb + imm] */ + thumb_access_memory(store, mem_imm, reg[rb] + (imm * 2), reg[rd], u16); + break; + + case 0x88 ... 0x8F: + /* LDRH rd, [rb + imm] */ + thumb_access_memory(load, mem_imm, reg[rb] + (imm * 2), reg[rd], u16); + break; + + case 0x90 ... 0x97: + /* STR r0..7, [sp + imm] */ + thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[(opcode >> 8) & 7], u32); + break; + + case 0x98 ... 0x9F: + /* LDR r0..7, [sp + imm] */ + thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[(opcode >> 8) & 7], u32); + break; + + case 0xA0 ... 0xA7: + /* ADD r0..7, pc, +imm */ + thumb_add_noflags(imm, ((opcode >> 8) & 7), (pc & ~2) + 4, (imm * 4)); + break; + + case 0xA8 ... 0xAF: + /* ADD r0..7, sp, +imm */ + thumb_add_noflags(imm, ((opcode >> 8) & 7), reg[REG_SP], (imm * 4)); + break; case 0xB0: case 0xB1: case 0xB2: - case 0xB3: - if((opcode >> 7) & 0x01) - { - /* ADD sp, -imm */ - thumb_add_noflags(add_sp, 13, reg[REG_SP], -(imm * 4)); - } - else - { - /* ADD sp, +imm */ - thumb_add_noflags(add_sp, 13, reg[REG_SP], (imm * 4)); - } - break; - - case 0xB4: - /* PUSH rlist */ - thumb_block_memory(store, down, no_op, 13); - break; - - case 0xB5: - /* PUSH rlist, lr */ - thumb_block_memory(store, push_lr, push_lr, 13); - break; - - case 0xBC: - /* POP rlist */ - thumb_block_memory(load, no_op, up, 13); - break; - - case 0xBD: - /* POP rlist, pc */ - thumb_block_memory(load, no_op, pop_pc, 13); - break; - - case 0xC0: - /* STMIA r0!, rlist */ - thumb_block_memory(store, no_op, up, 0); - break; - - case 0xC1: - /* STMIA r1!, rlist */ - thumb_block_memory(store, no_op, up, 1); - break; - - case 0xC2: - /* STMIA r2!, rlist */ - thumb_block_memory(store, no_op, up, 2); - break; - - case 0xC3: - /* STMIA r3!, rlist */ - thumb_block_memory(store, no_op, up, 3); - break; - - case 0xC4: - /* STMIA r4!, rlist */ - thumb_block_memory(store, no_op, up, 4); - break; - - case 0xC5: - /* STMIA r5!, rlist */ - thumb_block_memory(store, no_op, up, 5); - break; - - case 0xC6: - /* STMIA r6!, rlist */ - thumb_block_memory(store, no_op, up, 6); - break; - - case 0xC7: - /* STMIA r7!, rlist */ - thumb_block_memory(store, no_op, up, 7); - break; - - case 0xC8: - /* LDMIA r0!, rlist */ - thumb_block_memory(load, no_op, up, 0); - break; - - case 0xC9: - /* LDMIA r1!, rlist */ - thumb_block_memory(load, no_op, up, 1); - break; - - case 0xCA: - /* LDMIA r2!, rlist */ - thumb_block_memory(load, no_op, up, 2); - break; - - case 0xCB: - /* LDMIA r3!, rlist */ - thumb_block_memory(load, no_op, up, 3); - break; - - case 0xCC: - /* LDMIA r4!, rlist */ - thumb_block_memory(load, no_op, up, 4); - break; - - case 0xCD: - /* LDMIA r5!, rlist */ - thumb_block_memory(load, no_op, up, 5); - break; - - case 0xCE: - /* LDMIA r6!, rlist */ - thumb_block_memory(load, no_op, up, 6); - break; - - case 0xCF: - /* LDMIA r7!, rlist */ - thumb_block_memory(load, no_op, up, 7); - break; - - case 0xD0: - /* BEQ label */ - thumb_conditional_branch(z_flag == 1); - break; - - case 0xD1: - /* BNE label */ - thumb_conditional_branch(z_flag == 0); - break; - - case 0xD2: - /* BCS label */ - thumb_conditional_branch(c_flag == 1); - break; - - case 0xD3: - /* BCC label */ - thumb_conditional_branch(c_flag == 0); - break; - - case 0xD4: - /* BMI label */ - thumb_conditional_branch(n_flag == 1); - break; - - case 0xD5: - /* BPL label */ - thumb_conditional_branch(n_flag == 0); - break; - - case 0xD6: - /* BVS label */ - thumb_conditional_branch(v_flag == 1); - break; - - case 0xD7: - /* BVC label */ - thumb_conditional_branch(v_flag == 0); - break; - - case 0xD8: - /* BHI label */ - thumb_conditional_branch(c_flag & (z_flag ^ 1)); - break; - - case 0xD9: - /* BLS label */ - thumb_conditional_branch((c_flag == 0) | z_flag); - break; - - case 0xDA: - /* BGE label */ - thumb_conditional_branch(n_flag == v_flag); - break; - - case 0xDB: - /* BLT label */ - thumb_conditional_branch(n_flag != v_flag); - break; - - case 0xDC: - /* BGT label */ - thumb_conditional_branch((z_flag == 0) & (n_flag == v_flag)); - break; - - case 0xDD: - /* BLE label */ - thumb_conditional_branch(z_flag | (n_flag != v_flag)); - break; - - case 0xDF: - { - /* SWI comment */ - u32 swi_comment = opcode & 0xFF; - - switch(swi_comment) - { - default: - reg_mode[MODE_SUPERVISOR][6] = pc + 2; - spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; - reg[REG_PC] = 0x00000008; - thumb_update_pc(); - reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13; - set_cpu_mode(MODE_SUPERVISOR); - collapse_flags(); - goto arm_loop; - } - break; - } - - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - { - /* B label */ - thumb_decode_branch(); - thumb_pc_offset_update(((s32)(offset << 21) >> 20) + 4); - break; - } - - case 0xF0: - case 0xF1: - case 0xF2: - case 0xF3: - case 0xF4: - case 0xF5: - case 0xF6: - case 0xF7: - { - /* (low word) BL label */ - thumb_decode_branch(); - reg[REG_LR] = pc + 4 + ((s32)(offset << 21) >> 9); - thumb_pc_offset(2); - break; - } - - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - { - /* (high word) BL label */ - thumb_decode_branch(); - u32 lr = (pc + 2) | 0x01; - pc = reg[REG_LR] + (offset * 2); - reg[REG_LR] = lr; - reg[REG_PC] = pc; - break; - } - } + case 0xB3: + if((opcode >> 7) & 0x01) + { + /* ADD sp, -imm */ + thumb_add_noflags(add_sp, 13, reg[REG_SP], -(imm * 4)); + } + else + { + /* ADD sp, +imm */ + thumb_add_noflags(add_sp, 13, reg[REG_SP], (imm * 4)); + } + break; + + case 0xB4: + /* PUSH rlist */ + thumb_block_memory(store, down, no_op, 13); + break; + + case 0xB5: + /* PUSH rlist, lr */ + thumb_block_memory(store, push_lr, push_lr, 13); + break; + + case 0xBC: + /* POP rlist */ + thumb_block_memory(load, no_op, up, 13); + break; + + case 0xBD: + /* POP rlist, pc */ + thumb_block_memory(load, no_op, pop_pc, 13); + break; + + case 0xC0 ... 0xC7: + /* STMIA r0..7!, rlist */ + thumb_block_memory(store, no_op, up, ((opcode >> 8) & 7)); + break; + + case 0xC8 ... 0xCF: + /* LDMIA r0..7!, rlist */ + thumb_block_memory(load, no_op, up, ((opcode >> 8) & 7)); + break; + + case 0xD0: + /* BEQ label */ + thumb_conditional_branch(z_flag == 1); + break; + + case 0xD1: + /* BNE label */ + thumb_conditional_branch(z_flag == 0); + break; + + case 0xD2: + /* BCS label */ + thumb_conditional_branch(c_flag == 1); + break; + + case 0xD3: + /* BCC label */ + thumb_conditional_branch(c_flag == 0); + break; + + case 0xD4: + /* BMI label */ + thumb_conditional_branch(n_flag == 1); + break; + + case 0xD5: + /* BPL label */ + thumb_conditional_branch(n_flag == 0); + break; + + case 0xD6: + /* BVS label */ + thumb_conditional_branch(v_flag == 1); + break; + + case 0xD7: + /* BVC label */ + thumb_conditional_branch(v_flag == 0); + break; + + case 0xD8: + /* BHI label */ + thumb_conditional_branch(c_flag & (z_flag ^ 1)); + break; + + case 0xD9: + /* BLS label */ + thumb_conditional_branch((c_flag == 0) | z_flag); + break; + + case 0xDA: + /* BGE label */ + thumb_conditional_branch(n_flag == v_flag); + break; + + case 0xDB: + /* BLT label */ + thumb_conditional_branch(n_flag != v_flag); + break; + + case 0xDC: + /* BGT label */ + thumb_conditional_branch((z_flag == 0) & (n_flag == v_flag)); + break; + + case 0xDD: + /* BLE label */ + thumb_conditional_branch(z_flag | (n_flag != v_flag)); + break; + + case 0xDF: + { + /* SWI comment */ + u32 swi_comment = opcode & 0xFF; + + switch(swi_comment) + { + default: + reg_mode[MODE_SUPERVISOR][6] = pc + 2; + spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; + reg[REG_PC] = 0x00000008; + thumb_update_pc(); + reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13; + set_cpu_mode(MODE_SUPERVISOR); + collapse_flags(); + goto arm_loop; + } + break; + } + + case 0xE0 ... 0xE7: + { + /* B label */ + thumb_decode_branch(); + thumb_pc_offset_update(((s32)(offset << 21) >> 20) + 4); + break; + } + + case 0xF0 ... 0xF7: + { + /* (low word) BL label */ + thumb_decode_branch(); + reg[REG_LR] = pc + 4 + ((s32)(offset << 21) >> 9); + thumb_pc_offset(2); + break; + } + + case 0xF8 ... 0xFF: + { + /* (high word) BL label */ + thumb_decode_branch(); + u32 lr = (pc + 2) | 0x01; + pc = reg[REG_LR] + (offset * 2); + reg[REG_LR] = lr; + reg[REG_PC] = pc; + break; + } + } /* End of Execute THUMB instruction */ cycles_remaining -= cycles_per_instruction; diff --git a/cpu_threaded.c b/cpu_threaded.c index 832e212..ad2c098 100644 --- a/cpu_threaded.c +++ b/cpu_threaded.c @@ -309,6 +309,7 @@ void translate_icache_sync() { { \ /* MUL rd, rm, rs */ \ arm_multiply(no, no); \ + cycle_count += 2; /* variable 1..4, pick 2 as an aprox. */ \ } \ } \ else \ @@ -326,6 +327,7 @@ void translate_icache_sync() { case 0: \ /* MULS rd, rm, rs */ \ arm_multiply(no, yes); \ + cycle_count += 2; /* variable 1..4, pick 2 as an aprox. */ \ break; \ \ case 1: \ @@ -363,6 +365,7 @@ void translate_icache_sync() { { \ /* MLA rd, rm, rs, rn */ \ arm_multiply(yes, no); \ + cycle_count += 3; /* variable 2..5, pick 3 as an aprox. */ \ } \ } \ else \ @@ -380,6 +383,7 @@ void translate_icache_sync() { case 0: \ /* MLAS rd, rm, rs, rn */ \ arm_multiply(yes, yes); \ + cycle_count += 3; /* variable 2..5, pick 3 as an aprox. */ \ break; \ \ case 1: \ @@ -499,6 +503,7 @@ void translate_icache_sync() { { \ /* UMULL rd, rm, rs */ \ arm_multiply_long(u64, no, no); \ + cycle_count += 3; /* this is an aproximation :P */ \ } \ } \ else \ @@ -516,6 +521,7 @@ void translate_icache_sync() { case 0: \ /* UMULLS rdlo, rdhi, rm, rs */ \ arm_multiply_long(u64, no, yes); \ + cycle_count += 3; /* this is an aproximation :P */ \ break; \ \ case 1: \ @@ -553,6 +559,7 @@ void translate_icache_sync() { { \ /* UMLAL rd, rm, rs */ \ arm_multiply_long(u64_add, yes, no); \ + cycle_count += 3; /* Between 2 and 5 cycles? */ \ } \ } \ else \ @@ -570,6 +577,7 @@ void translate_icache_sync() { case 0: \ /* UMLALS rdlo, rdhi, rm, rs */ \ arm_multiply_long(u64_add, yes, yes); \ + cycle_count += 3; /* Between 2 and 5 cycles? */ \ break; \ \ case 1: \ @@ -607,6 +615,7 @@ void translate_icache_sync() { { \ /* SMULL rd, rm, rs */ \ arm_multiply_long(s64, no, no); \ + cycle_count += 2; /* Between 1 and 4 cycles? */ \ } \ } \ else \ @@ -624,6 +633,7 @@ void translate_icache_sync() { case 0: \ /* SMULLS rdlo, rdhi, rm, rs */ \ arm_multiply_long(s64, no, yes); \ + cycle_count += 2; /* Between 1 and 4 cycles? */ \ break; \ \ case 1: \ @@ -661,6 +671,7 @@ void translate_icache_sync() { { \ /* SMLAL rd, rm, rs */ \ arm_multiply_long(s64_add, yes, no); \ + cycle_count += 3; /* Between 2 and 5 cycles? */ \ } \ } \ else \ @@ -678,6 +689,7 @@ void translate_icache_sync() { case 0: \ /* SMLALS rdlo, rdhi, rm, rs */ \ arm_multiply_long(s64_add, yes, yes); \ + cycle_count += 3; /* Between 2 and 5 cycles? */ \ break; \ \ case 1: \ @@ -1717,8 +1729,9 @@ void translate_icache_sync() { last_opcode = opcode; \ opcode = address16(pc_address_block, (pc & 0x7FFF)); \ emit_trace_thumb_instruction(pc); \ + u8 hiop = opcode >> 8; \ \ - switch((opcode >> 8) & 0xFF) \ + switch(hiop) \ { \ case 0x00 ... 0x07: \ /* LSL rd, rs, imm */ \ @@ -1755,165 +1768,45 @@ void translate_icache_sync() { thumb_data_proc(add_sub_imm, subs, imm, rd, rs, imm); \ break; \ \ - case 0x20: \ - /* MOV r0, imm */ \ - thumb_data_proc_unary(imm, movs, imm, 0, imm); \ - break; \ - \ - case 0x21: \ - /* MOV r1, imm */ \ - thumb_data_proc_unary(imm, movs, imm, 1, imm); \ - break; \ - \ - case 0x22: \ - /* MOV r2, imm */ \ - thumb_data_proc_unary(imm, movs, imm, 2, imm); \ - break; \ - \ - case 0x23: \ - /* MOV r3, imm */ \ - thumb_data_proc_unary(imm, movs, imm, 3, imm); \ - break; \ - \ - case 0x24: \ - /* MOV r4, imm */ \ - thumb_data_proc_unary(imm, movs, imm, 4, imm); \ - break; \ - \ - case 0x25: \ - /* MOV r5, imm */ \ - thumb_data_proc_unary(imm, movs, imm, 5, imm); \ - break; \ - \ - case 0x26: \ - /* MOV r6, imm */ \ - thumb_data_proc_unary(imm, movs, imm, 6, imm); \ - break; \ - \ - case 0x27: \ - /* MOV r7, imm */ \ - thumb_data_proc_unary(imm, movs, imm, 7, imm); \ - break; \ - \ - case 0x28: \ - /* CMP r0, imm */ \ - thumb_data_proc_test(imm, cmp, imm, 0, imm); \ - break; \ - \ - case 0x29: \ - /* CMP r1, imm */ \ - thumb_data_proc_test(imm, cmp, imm, 1, imm); \ - break; \ - \ - case 0x2A: \ - /* CMP r2, imm */ \ - thumb_data_proc_test(imm, cmp, imm, 2, imm); \ - break; \ - \ - case 0x2B: \ - /* CMP r3, imm */ \ - thumb_data_proc_test(imm, cmp, imm, 3, imm); \ - break; \ - \ - case 0x2C: \ - /* CMP r4, imm */ \ - thumb_data_proc_test(imm, cmp, imm, 4, imm); \ - break; \ - \ - case 0x2D: \ - /* CMP r5, imm */ \ - thumb_data_proc_test(imm, cmp, imm, 5, imm); \ - break; \ - \ - case 0x2E: \ - /* CMP r6, imm */ \ - thumb_data_proc_test(imm, cmp, imm, 6, imm); \ - break; \ - \ - case 0x2F: \ - /* CMP r7, imm */ \ - thumb_data_proc_test(imm, cmp, imm, 7, imm); \ - break; \ - \ - case 0x30: \ - /* ADD r0, imm */ \ - thumb_data_proc(imm, adds, imm, 0, 0, imm); \ - break; \ - \ - case 0x31: \ - /* ADD r1, imm */ \ - thumb_data_proc(imm, adds, imm, 1, 1, imm); \ - break; \ - \ - case 0x32: \ - /* ADD r2, imm */ \ - thumb_data_proc(imm, adds, imm, 2, 2, imm); \ - break; \ - \ - case 0x33: \ - /* ADD r3, imm */ \ - thumb_data_proc(imm, adds, imm, 3, 3, imm); \ - break; \ - \ - case 0x34: \ - /* ADD r4, imm */ \ - thumb_data_proc(imm, adds, imm, 4, 4, imm); \ - break; \ - \ - case 0x35: \ - /* ADD r5, imm */ \ - thumb_data_proc(imm, adds, imm, 5, 5, imm); \ - break; \ - \ - case 0x36: \ - /* ADD r6, imm */ \ - thumb_data_proc(imm, adds, imm, 6, 6, imm); \ - break; \ - \ - case 0x37: \ - /* ADD r7, imm */ \ - thumb_data_proc(imm, adds, imm, 7, 7, imm); \ - break; \ - \ - case 0x38: \ - /* SUB r0, imm */ \ - thumb_data_proc(imm, subs, imm, 0, 0, imm); \ - break; \ - \ - case 0x39: \ - /* SUB r1, imm */ \ - thumb_data_proc(imm, subs, imm, 1, 1, imm); \ - break; \ - \ - case 0x3A: \ - /* SUB r2, imm */ \ - thumb_data_proc(imm, subs, imm, 2, 2, imm); \ - break; \ - \ - case 0x3B: \ - /* SUB r3, imm */ \ - thumb_data_proc(imm, subs, imm, 3, 3, imm); \ - break; \ - \ - case 0x3C: \ - /* SUB r4, imm */ \ - thumb_data_proc(imm, subs, imm, 4, 4, imm); \ - break; \ - \ - case 0x3D: \ - /* SUB r5, imm */ \ - thumb_data_proc(imm, subs, imm, 5, 5, imm); \ - break; \ - \ - case 0x3E: \ - /* SUB r6, imm */ \ - thumb_data_proc(imm, subs, imm, 6, 6, imm); \ - break; \ - \ - case 0x3F: \ - /* SUB r7, imm */ \ - thumb_data_proc(imm, subs, imm, 7, 7, imm); \ - break; \ + /* MOV r0..7, imm */ \ + case 0x20: thumb_data_proc_unary(imm, movs, imm, 0, imm); break; \ + case 0x21: thumb_data_proc_unary(imm, movs, imm, 1, imm); break; \ + case 0x22: thumb_data_proc_unary(imm, movs, imm, 2, imm); break; \ + case 0x23: thumb_data_proc_unary(imm, movs, imm, 3, imm); break; \ + case 0x24: thumb_data_proc_unary(imm, movs, imm, 4, imm); break; \ + case 0x25: thumb_data_proc_unary(imm, movs, imm, 5, imm); break; \ + case 0x26: thumb_data_proc_unary(imm, movs, imm, 6, imm); break; \ + case 0x27: thumb_data_proc_unary(imm, movs, imm, 7, imm); break; \ + \ + /* CMP r0, imm */ \ + case 0x28: thumb_data_proc_test(imm, cmp, imm, 0, imm); break; \ + case 0x29: thumb_data_proc_test(imm, cmp, imm, 1, imm); break; \ + case 0x2A: thumb_data_proc_test(imm, cmp, imm, 2, imm); break; \ + case 0x2B: thumb_data_proc_test(imm, cmp, imm, 3, imm); break; \ + case 0x2C: thumb_data_proc_test(imm, cmp, imm, 4, imm); break; \ + case 0x2D: thumb_data_proc_test(imm, cmp, imm, 5, imm); break; \ + case 0x2E: thumb_data_proc_test(imm, cmp, imm, 6, imm); break; \ + case 0x2F: thumb_data_proc_test(imm, cmp, imm, 7, imm); break; \ + \ + /* ADD r0..7, imm */ \ + case 0x30: thumb_data_proc(imm, adds, imm, 0, 0, imm); break; \ + case 0x31: thumb_data_proc(imm, adds, imm, 1, 1, imm); break; \ + case 0x32: thumb_data_proc(imm, adds, imm, 2, 2, imm); break; \ + case 0x33: thumb_data_proc(imm, adds, imm, 3, 3, imm); break; \ + case 0x34: thumb_data_proc(imm, adds, imm, 4, 4, imm); break; \ + case 0x35: thumb_data_proc(imm, adds, imm, 5, 5, imm); break; \ + case 0x36: thumb_data_proc(imm, adds, imm, 6, 6, imm); break; \ + case 0x37: thumb_data_proc(imm, adds, imm, 7, 7, imm); break; \ + \ + /* SUB r0..7, imm */ \ + case 0x38: thumb_data_proc(imm, subs, imm, 0, 0, imm); break; \ + case 0x39: thumb_data_proc(imm, subs, imm, 1, 1, imm); break; \ + case 0x3A: thumb_data_proc(imm, subs, imm, 2, 2, imm); break; \ + case 0x3B: thumb_data_proc(imm, subs, imm, 3, 3, imm); break; \ + case 0x3C: thumb_data_proc(imm, subs, imm, 4, 4, imm); break; \ + case 0x3D: thumb_data_proc(imm, subs, imm, 5, 5, imm); break; \ + case 0x3E: thumb_data_proc(imm, subs, imm, 6, 6, imm); break; \ + case 0x3F: thumb_data_proc(imm, subs, imm, 7, 7, imm); break; \ \ case 0x40: \ switch((opcode >> 6) & 0x03) \ @@ -2001,6 +1894,7 @@ void translate_icache_sync() { case 0x01: \ /* MUL rd, rs */ \ thumb_data_proc(alu_op, muls, reg, rd, rd, rs); \ + cycle_count += 2; /* Between 1 and 4 extra cycles */ \ break; \ \ case 0x02: \ @@ -2035,52 +1929,21 @@ void translate_icache_sync() { thumb_bx(); \ break; \ \ - case 0x48: \ - /* LDR r0, [pc + imm] */ \ - thumb_access_memory(load, imm, 0, 0, 0, pc_relative, \ - (pc & ~2) + (imm * 4) + 4, u32); \ - break; \ - \ - case 0x49: \ - /* LDR r1, [pc + imm] */ \ - thumb_access_memory(load, imm, 1, 0, 0, pc_relative, \ - (pc & ~2) + (imm * 4) + 4, u32); \ - break; \ - \ - case 0x4A: \ - /* LDR r2, [pc + imm] */ \ - thumb_access_memory(load, imm, 2, 0, 0, pc_relative, \ - (pc & ~2) + (imm * 4) + 4, u32); \ - break; \ - \ - case 0x4B: \ - /* LDR r3, [pc + imm] */ \ - thumb_access_memory(load, imm, 3, 0, 0, pc_relative, \ - (pc & ~2) + (imm * 4) + 4, u32); \ - break; \ - \ - case 0x4C: \ - /* LDR r4, [pc + imm] */ \ - thumb_access_memory(load, imm, 4, 0, 0, pc_relative, \ - (pc & ~2) + (imm * 4) + 4, u32); \ - break; \ - \ - case 0x4D: \ - /* LDR r5, [pc + imm] */ \ - thumb_access_memory(load, imm, 5, 0, 0, pc_relative, \ - (pc & ~2) + (imm * 4) + 4, u32); \ - break; \ - \ - case 0x4E: \ - /* LDR r6, [pc + imm] */ \ - thumb_access_memory(load, imm, 6, 0, 0, pc_relative, \ - (pc & ~2) + (imm * 4) + 4, u32); \ - break; \ - \ - case 0x4F: \ - /* LDR r7, [pc + imm] */ \ - thumb_access_memory(load, imm, 7, 0, 0, pc_relative, \ - (pc & ~2) + (imm * 4) + 4, u32); \ + case 0x48 ... 0x4F: \ + /* LDR r0..7, [pc + imm] */ \ + { \ + thumb_decode_imm(); \ + u32 rdreg = (hiop & 7); \ + u32 aoff = (pc & ~2) + (imm*4) + 4; \ + /* ROM + same page -> optimize as const load */ \ + if (translation_region == TRANSLATION_REGION_ROM && \ + (((aoff + 4) >> 15) == (pc >> 15))) { \ + u32 value = address32(pc_address_block, (aoff & 0x7FFF)); \ + thumb_load_pc_pool_const(rdreg, value); \ + } else { \ + thumb_access_memory(load, imm, rdreg, 0, 0, pc_relative, aoff, u32);\ + } \ + } \ break; \ \ case 0x50 ... 0x51: \ @@ -2155,165 +2018,77 @@ void translate_icache_sync() { thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 2), u16); \ break; \ \ + /* STR r0..7, [sp + imm] */ \ case 0x90: \ - /* STR r0, [sp + imm] */ \ thumb_access_memory(store, imm, 0, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x91: \ - /* STR r1, [sp + imm] */ \ thumb_access_memory(store, imm, 1, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x92: \ - /* STR r2, [sp + imm] */ \ thumb_access_memory(store, imm, 2, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x93: \ - /* STR r3, [sp + imm] */ \ thumb_access_memory(store, imm, 3, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x94: \ - /* STR r4, [sp + imm] */ \ thumb_access_memory(store, imm, 4, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x95: \ - /* STR r5, [sp + imm] */ \ thumb_access_memory(store, imm, 5, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x96: \ - /* STR r6, [sp + imm] */ \ thumb_access_memory(store, imm, 6, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x97: \ - /* STR r7, [sp + imm] */ \ thumb_access_memory(store, imm, 7, 13, 0, reg_imm_sp, imm, u32); \ break; \ \ + /* LDR r0..7, [sp + imm] */ \ case 0x98: \ - /* LDR r0, [sp + imm] */ \ thumb_access_memory(load, imm, 0, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x99: \ - /* LDR r1, [sp + imm] */ \ thumb_access_memory(load, imm, 1, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x9A: \ - /* LDR r2, [sp + imm] */ \ thumb_access_memory(load, imm, 2, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x9B: \ - /* LDR r3, [sp + imm] */ \ thumb_access_memory(load, imm, 3, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x9C: \ - /* LDR r4, [sp + imm] */ \ thumb_access_memory(load, imm, 4, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x9D: \ - /* LDR r5, [sp + imm] */ \ thumb_access_memory(load, imm, 5, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x9E: \ - /* LDR r6, [sp + imm] */ \ thumb_access_memory(load, imm, 6, 13, 0, reg_imm_sp, imm, u32); \ break; \ - \ case 0x9F: \ - /* LDR r7, [sp + imm] */ \ thumb_access_memory(load, imm, 7, 13, 0, reg_imm_sp, imm, u32); \ break; \ \ - case 0xA0: \ - /* ADD r0, pc, +imm */ \ - thumb_load_pc(0); \ - break; \ - \ - case 0xA1: \ - /* ADD r1, pc, +imm */ \ - thumb_load_pc(1); \ - break; \ - \ - case 0xA2: \ - /* ADD r2, pc, +imm */ \ - thumb_load_pc(2); \ - break; \ - \ - case 0xA3: \ - /* ADD r3, pc, +imm */ \ - thumb_load_pc(3); \ - break; \ - \ - case 0xA4: \ - /* ADD r4, pc, +imm */ \ - thumb_load_pc(4); \ - break; \ - \ - case 0xA5: \ - /* ADD r5, pc, +imm */ \ - thumb_load_pc(5); \ - break; \ - \ - case 0xA6: \ - /* ADD r6, pc, +imm */ \ - thumb_load_pc(6); \ - break; \ - \ - case 0xA7: \ - /* ADD r7, pc, +imm */ \ - thumb_load_pc(7); \ - break; \ - \ - case 0xA8: \ - /* ADD r0, sp, +imm */ \ - thumb_load_sp(0); \ - break; \ - \ - case 0xA9: \ - /* ADD r1, sp, +imm */ \ - thumb_load_sp(1); \ - break; \ - \ - case 0xAA: \ - /* ADD r2, sp, +imm */ \ - thumb_load_sp(2); \ - break; \ - \ - case 0xAB: \ - /* ADD r3, sp, +imm */ \ - thumb_load_sp(3); \ - break; \ - \ - case 0xAC: \ - /* ADD r4, sp, +imm */ \ - thumb_load_sp(4); \ - break; \ - \ - case 0xAD: \ - /* ADD r5, sp, +imm */ \ - thumb_load_sp(5); \ - break; \ - \ - case 0xAE: \ - /* ADD r6, sp, +imm */ \ - thumb_load_sp(6); \ - break; \ - \ - case 0xAF: \ - /* ADD r7, sp, +imm */ \ - thumb_load_sp(7); \ - break; \ + /* ADD r0..7, pc, +imm */ \ + case 0xA0: thumb_load_pc(0); break; \ + case 0xA1: thumb_load_pc(1); break; \ + case 0xA2: thumb_load_pc(2); break; \ + case 0xA3: thumb_load_pc(3); break; \ + case 0xA4: thumb_load_pc(4); break; \ + case 0xA5: thumb_load_pc(5); break; \ + case 0xA6: thumb_load_pc(6); break; \ + case 0xA7: thumb_load_pc(7); break; \ + \ + /* ADD r0..7, sp, +imm */ \ + case 0xA8: thumb_load_sp(0); break; \ + case 0xA9: thumb_load_sp(1); break; \ + case 0xAA: thumb_load_sp(2); break; \ + case 0xAB: thumb_load_sp(3); break; \ + case 0xAC: thumb_load_sp(4); break; \ + case 0xAD: thumb_load_sp(5); break; \ + case 0xAE: thumb_load_sp(6); break; \ + case 0xAF: thumb_load_sp(7); break; \ \ case 0xB0 ... 0xB3: \ if((opcode >> 7) & 0x01) \ @@ -3338,6 +3113,11 @@ s32 translate_block_arm(u32 pc, translation_region_type block_data[block_data_position].block_offset = translation_ptr; arm_base_cycles(); + if (pc == cheat_master_hook) + { + arm_process_cheats(); + } + translate_arm_instruction(); block_data_position++; @@ -3551,6 +3331,11 @@ s32 translate_block_thumb(u32 pc, translation_region_type block_data[block_data_position].block_offset = translation_ptr; thumb_base_cycles(); + if (pc == cheat_master_hook) + { + thumb_process_cheats(); + } + translate_thumb_instruction(); block_data_position++; diff --git a/gba_memory.c b/gba_memory.c index d2af846..f397797 100644 --- a/gba_memory.c +++ b/gba_memory.c @@ -36,7 +36,7 @@ gbc_sound_channel[channel].envelope_status = (envelope_ticks != 0); \ gbc_sound_channel[channel].envelope_volume = initial_volume; \ gbc_sound_update = 1; \ - address16(io_registers, address) = value; \ + address16(io_registers, address) = eswap16(value); \ } \ #define gbc_sound_tone_control_high(channel, address) \ @@ -57,7 +57,7 @@ } \ \ gbc_sound_update = 1; \ - address16(io_registers, address) = value; \ + address16(io_registers, address) = eswap16(value); \ } \ #define gbc_sound_tone_control_sweep() \ @@ -69,7 +69,7 @@ gbc_sound_channel[0].sweep_ticks = sweep_ticks; \ gbc_sound_channel[0].sweep_initial_ticks = sweep_ticks; \ gbc_sound_update = 1; \ - address16(io_registers, 0x60) = value; \ + write_ioreg(REG_SOUND1CNT_L, value); \ } \ #define gbc_sound_wave_control() \ @@ -81,7 +81,7 @@ gbc_sound_channel[2].master_enable = 1; \ \ gbc_sound_update = 1; \ - address16(io_registers, 0x70) = value; \ + write_ioreg(REG_SOUND3CNT_L, value); \ } \ static u32 gbc_sound_wave_volume[4] = { 0, 16384, 8192, 4096 }; @@ -95,7 +95,7 @@ static u32 gbc_sound_wave_volume[4] = { 0, 16384, 8192, 4096 }; gbc_sound_channel[2].wave_volume = \ gbc_sound_wave_volume[(value >> 13) & 0x03]; \ gbc_sound_update = 1; \ - address16(io_registers, 0x72) = value; \ + write_ioreg(REG_SOUND3CNT_H, value); \ } \ #define gbc_sound_tone_control_high_wave() \ @@ -111,7 +111,7 @@ static u32 gbc_sound_wave_volume[4] = { 0, 16384, 8192, 4096 }; gbc_sound_channel[2].active_flag = 1; \ } \ gbc_sound_update = 1; \ - address16(io_registers, 0x74) = value; \ + write_ioreg(REG_SOUND3CNT_X, value); \ } \ #define gbc_sound_noise_control() \ @@ -142,7 +142,7 @@ static u32 gbc_sound_wave_volume[4] = { 0, 16384, 8192, 4096 }; gbc_sound_channel[3].envelope_initial_volume; \ } \ gbc_sound_update = 1; \ - address16(io_registers, 0x7C) = value; \ + write_ioreg(REG_SOUND4CNT_H, value); \ } \ static void gbc_trigger_sound(u32 value) @@ -157,7 +157,7 @@ static void gbc_trigger_sound(u32 value) gbc_sound_channel[channel].status = ((value >> (channel + 8)) & 0x01) | ((value >> (channel + 11)) & 0x03); } - address16(io_registers, 0x80) = value; + write_ioreg(REG_SOUNDCNT_L, value); } #define trigger_sound() \ @@ -176,7 +176,7 @@ static void gbc_trigger_sound(u32 value) sound_reset_fifo(0); \ if((value >> 15) & 0x01) \ sound_reset_fifo(1); \ - address16(io_registers, 0x82) = value; \ + write_ioreg(REG_SOUNDCNT_H, value); \ } \ static void sound_control_x(u32 value) @@ -194,8 +194,8 @@ static void sound_control_x(u32 value) sound_on = 0; } - address16(io_registers, 0x84) = - (address16(io_registers, 0x84) & 0x000F) | (value & 0xFFF0); + address16(io_registers, 0x84) = eswap16( + (readaddress16(io_registers, 0x84) & 0x000F) | (value & 0xFFF0)); } #define sound_update_frequency_step(timer_number) \ @@ -239,7 +239,7 @@ static void trigger_timer(u32 timer_number, u32 value) timer[timer_number].prescale = prescale; timer[timer_number].irq = (value >> 6) & 0x01; - address16(io_registers, 0x100 + (timer_number * 4)) = -timer_reload; + write_ioreg(REG_TM0D + (timer_number * 2), (u32)(-timer_reload)); timer_reload <<= prescale; timer[timer_number].count = timer_reload; @@ -267,7 +267,7 @@ static void trigger_timer(u32 timer_number, u32 value) timer[timer_number].stop_cpu_ticks = cpu_ticks; } } - address16(io_registers, 0x102 + (timer_number * 4)) = value; + write_ioreg(REG_TM0CNT + (timer_number * 2), value); } // This table is configured for sequential access on system defaults @@ -323,9 +323,6 @@ u32 gamepak_size; dma_transfer_type dma[4]; -u8 *memory_regions[16]; -u32 memory_limits[16]; - typedef struct { u32 page_timestamp; @@ -463,7 +460,7 @@ void function_cc write_eeprom(u32 unused_address, u32 value) if(eeprom_size == EEPROM_512_BYTE) { eeprom_address = - (address16(eeprom_buffer, 0) >> 2) * 8; + (readaddress16(eeprom_buffer, 0) >> 2) * 8; } else { @@ -513,10 +510,10 @@ void function_cc write_eeprom(u32 unused_address, u32 value) u32 gamepak_index = address >> 15; \ u8 *map = memory_map_read[gamepak_index]; \ \ - if(!map) \ + if(!map) \ map = load_gamepak_page(gamepak_index & 0x3FF); \ \ - value = address##type(map, address & 0x7FFF) \ + value = readaddress##type(map, address & 0x7FFF) \ #define read_open8() \ if(!(reg[REG_CPSR] & 0x20)) \ @@ -585,29 +582,29 @@ u32 function_cc read_eeprom(void) case 0x00: \ /* BIOS */ \ if(reg[REG_PC] >= 0x4000) \ - value = address##type(&bios_read_protect, address & 0x03); \ + value = readaddress##type(&bios_read_protect, address & 0x03); \ else \ - value = address##type(bios_rom, address & 0x3FFF); \ + value = readaddress##type(bios_rom, address & 0x3FFF); \ break; \ \ case 0x02: \ /* external work RAM */ \ - value = address##type(ewram, (address & 0x3FFFF)); \ + value = readaddress##type(ewram, (address & 0x3FFFF)); \ break; \ \ case 0x03: \ /* internal work RAM */ \ - value = address##type(iwram, (address & 0x7FFF) + 0x8000); \ + value = readaddress##type(iwram, (address & 0x7FFF) + 0x8000); \ break; \ \ case 0x04: \ /* I/O registers */ \ - value = address##type(io_registers, address & 0x3FF); \ + value = readaddress##type(io_registers, address & 0x3FF); \ break; \ \ case 0x05: \ /* palette RAM */ \ - value = address##type(palette_ram, address & 0x3FF); \ + value = readaddress##type(palette_ram, address & 0x3FF); \ break; \ \ case 0x06: \ @@ -616,12 +613,12 @@ u32 function_cc read_eeprom(void) if(address > 0x18000) \ address -= 0x8000; \ \ - value = address##type(vram, address); \ + value = readaddress##type(vram, address); \ break; \ \ case 0x07: \ /* OAM RAM */ \ - value = address##type(oam_ram, address & 0x3FF); \ + value = readaddress##type(oam_ram, address & 0x3FF); \ break; \ \ case 0x08: \ @@ -665,12 +662,12 @@ static cpu_alert_type trigger_dma(u32 dma_number, u32 value) if(dma[dma_number].start_type == DMA_INACTIVE) { u32 start_type = (value >> 12) & 0x03; - u32 dest_address = address32(io_registers, (dma_number * 12) + 0xB4) & + u32 dest_address = readaddress32(io_registers, (dma_number * 12) + 0xB4) & 0xFFFFFFF; dma[dma_number].dma_channel = dma_number; dma[dma_number].source_address = - address32(io_registers, (dma_number * 12) + 0xB0) & 0xFFFFFFF; + readaddress32(io_registers, (dma_number * 12) + 0xB0) & 0xFFFFFFF; dma[dma_number].dest_address = dest_address; dma[dma_number].source_direction = (value >> 7) & 0x03; dma[dma_number].repeat_type = (value >> 9) & 0x01; @@ -691,7 +688,7 @@ static cpu_alert_type trigger_dma(u32 dma_number, u32 value) } else { - u32 length = address16(io_registers, (dma_number * 12) + 0xB8); + u32 length = read_ioreg(REG_DMA0CNT_L + (dma_number * 6)); if((dma_number == 3) && ((dest_address >> 24) == 0x0D) && ((length & 0x1F) == 17)) @@ -713,7 +710,7 @@ static cpu_alert_type trigger_dma(u32 dma_number, u32 value) dma[dma_number].dest_direction = (value >> 5) & 0x03; } - address16(io_registers, (dma_number * 12) + 0xBA) = value; + write_ioreg(REG_DMA0CNT_H + (dma_number * 6), value); if(start_type == DMA_START_IMMEDIATELY) return dma_transfer(dma + dma_number); } @@ -722,7 +719,7 @@ static cpu_alert_type trigger_dma(u32 dma_number, u32 value) { dma[dma_number].start_type = DMA_INACTIVE; dma[dma_number].direct_sound_channel = DMA_NO_DIRECT_SOUND; - address16(io_registers, (dma_number * 12) + 0xBA) = value; + write_ioreg(REG_DMA0CNT_H + (dma_number * 6), value); } return CPU_ALERT_NONE; @@ -736,10 +733,10 @@ static cpu_alert_type trigger_dma(u32 dma_number, u32 value) value = ((address8(io_registers, address + 1)) << 8) | value \ #define access_register16_high(address) \ - value = (value << 16) | (address16(io_registers, address)) \ + value = (value << 16) | (readaddress16(io_registers, address)) \ #define access_register16_low(address) \ - value = ((address16(io_registers, address + 2)) << 16) | value \ + value = ((readaddress16(io_registers, address + 2)) << 16) | value \ cpu_alert_type function_cc write_io_register8(u32 address, u32 value) { @@ -748,7 +745,7 @@ cpu_alert_type function_cc write_io_register8(u32 address, u32 value) { case 0x00: { - u32 dispcnt = io_registers[REG_DISPCNT]; + u32 dispcnt = read_ioreg(REG_DISPCNT); if((value & 0x07) != (dispcnt & 0x07)) reg[OAM_UPDATED] = 1; @@ -773,28 +770,28 @@ cpu_alert_type function_cc write_io_register8(u32 address, u32 value) access_register8_low(0x28); access_register16_low(0x28); affine_reference_x[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x28) = value; + address32(io_registers, 0x28) = eswap32(value); break; case 0x29: access_register8_high(0x28); access_register16_low(0x28); affine_reference_x[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x28) = value; + address32(io_registers, 0x28) = eswap32(value); break; case 0x2A: access_register8_low(0x2A); access_register16_high(0x28); affine_reference_x[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x28) = value; + address32(io_registers, 0x28) = eswap32(value); break; case 0x2B: access_register8_high(0x2A); access_register16_high(0x28); affine_reference_x[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x28) = value; + address32(io_registers, 0x28) = eswap32(value); break; // BG2 reference Y @@ -802,28 +799,28 @@ cpu_alert_type function_cc write_io_register8(u32 address, u32 value) access_register8_low(0x2C); access_register16_low(0x2C); affine_reference_y[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x2C) = value; + address32(io_registers, 0x2C) = eswap32(value); break; case 0x2D: access_register8_high(0x2C); access_register16_low(0x2C); affine_reference_y[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x2C) = value; + address32(io_registers, 0x2C) = eswap32(value); break; case 0x2E: access_register8_low(0x2E); access_register16_high(0x2C); affine_reference_y[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x2C) = value; + address32(io_registers, 0x2C) = eswap32(value); break; case 0x2F: access_register8_high(0x2E); access_register16_high(0x2C); affine_reference_y[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x2C) = value; + address32(io_registers, 0x2C) = eswap32(value); break; // BG3 reference X @@ -831,28 +828,28 @@ cpu_alert_type function_cc write_io_register8(u32 address, u32 value) access_register8_low(0x38); access_register16_low(0x38); affine_reference_x[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x38) = value; + address32(io_registers, 0x38) = eswap32(value); break; case 0x39: access_register8_high(0x38); access_register16_low(0x38); affine_reference_x[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x38) = value; + address32(io_registers, 0x38) = eswap32(value); break; case 0x3A: access_register8_low(0x3A); access_register16_high(0x38); affine_reference_x[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x38) = value; + address32(io_registers, 0x38) = eswap32(value); break; case 0x3B: access_register8_high(0x3A); access_register16_high(0x38); affine_reference_x[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x38) = value; + address32(io_registers, 0x38) = eswap32(value); break; // BG3 reference Y @@ -860,28 +857,28 @@ cpu_alert_type function_cc write_io_register8(u32 address, u32 value) access_register8_low(0x3C); access_register16_low(0x3C); affine_reference_y[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x3C) = value; + address32(io_registers, 0x3C) = eswap32(value); break; case 0x3D: access_register8_high(0x3C); access_register16_low(0x3C); affine_reference_y[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x3C) = value; + address32(io_registers, 0x3C) = eswap32(value); break; case 0x3E: access_register8_low(0x3E); access_register16_high(0x3C); affine_reference_y[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x3C) = value; + address32(io_registers, 0x3C) = eswap32(value); break; case 0x3F: access_register8_high(0x3E); access_register16_high(0x3C); affine_reference_y[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x3C) = value; + address32(io_registers, 0x3C) = eswap32(value); break; // Sound 1 control sweep @@ -1165,18 +1162,17 @@ cpu_alert_type function_cc write_io_register16(u32 address, u32 value) { case 0x00: { - u32 dispcnt = io_registers[REG_DISPCNT]; + u32 dispcnt = read_ioreg(REG_DISPCNT); if((value & 0x07) != (dispcnt & 0x07)) reg[OAM_UPDATED] = 1; - address16(io_registers, 0x00) = value; + write_ioreg(REG_DISPCNT, value); break; } // DISPSTAT case 0x04: - address16(io_registers, 0x04) = - (address16(io_registers, 0x04) & 0x07) | (value & ~0x07); + write_ioreg(REG_DISPSTAT, (read_ioreg(REG_DISPSTAT) & 0x07) | (value & ~0x07)); break; // VCOUNT @@ -1187,26 +1183,26 @@ cpu_alert_type function_cc write_io_register16(u32 address, u32 value) case 0x28: access_register16_low(0x28); affine_reference_x[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x28) = value; + address32(io_registers, 0x28) = eswap32(value); break; case 0x2A: access_register16_high(0x28); affine_reference_x[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x28) = value; + address32(io_registers, 0x28) = eswap32(value); break; // BG2 reference Y case 0x2C: access_register16_low(0x2C); affine_reference_y[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x2C) = value; + address32(io_registers, 0x2C) = eswap32(value); break; case 0x2E: access_register16_high(0x2C); affine_reference_y[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x2C) = value; + address32(io_registers, 0x2C) = eswap32(value); break; // BG3 reference X @@ -1214,26 +1210,26 @@ cpu_alert_type function_cc write_io_register16(u32 address, u32 value) case 0x38: access_register16_low(0x38); affine_reference_x[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x38) = value; + address32(io_registers, 0x38) = eswap32(value); break; case 0x3A: access_register16_high(0x38); affine_reference_x[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x38) = value; + address32(io_registers, 0x38) = eswap32(value); break; // BG3 reference Y case 0x3C: access_register16_low(0x3C); affine_reference_y[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x3C) = value; + address32(io_registers, 0x3C) = eswap32(value); break; case 0x3E: access_register16_high(0x3C); affine_reference_y[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x3C) = value; + address32(io_registers, 0x3C) = eswap32(value); break; // Sound 1 control sweep @@ -1318,7 +1314,7 @@ cpu_alert_type function_cc write_io_register16(u32 address, u32 value) case 0x9D: case 0x9E: gbc_sound_wave_update = 1; - address16(io_registers, address) = value; + address16(io_registers, address) = eswap16(value); break; // Sound FIFO A @@ -1387,7 +1383,7 @@ cpu_alert_type function_cc write_io_register16(u32 address, u32 value) // Interrupt flag case 0x202: - address16(io_registers, 0x202) &= ~value; + write_ioreg(REG_IF, read_ioreg(REG_IF) & (~value)); break; // WAITCNT @@ -1404,7 +1400,7 @@ cpu_alert_type function_cc write_io_register16(u32 address, u32 value) return CPU_ALERT_HALT; default: - address16(io_registers, address) = value; + address16(io_registers, address) = eswap16(value); break; } @@ -1419,25 +1415,25 @@ cpu_alert_type function_cc write_io_register32(u32 address, u32 value) // BG2 reference X case 0x28: affine_reference_x[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x28) = value; + address32(io_registers, 0x28) = eswap32(value); break; // BG2 reference Y case 0x2C: affine_reference_y[0] = (s32)(value << 4) >> 4; - address32(io_registers, 0x2C) = value; + address32(io_registers, 0x2C) = eswap32(value); break; // BG3 reference X case 0x38: affine_reference_x[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x38) = value; + address32(io_registers, 0x38) = eswap32(value); break; // BG3 reference Y case 0x3C: affine_reference_y[1] = (s32)(value << 4) >> 4; - address32(io_registers, 0x3C) = value; + address32(io_registers, 0x3C) = eswap32(value); break; // Sound FIFO A @@ -1473,7 +1469,7 @@ cpu_alert_type function_cc write_io_register32(u32 address, u32 value) #define write_palette16(address, value) \ { \ u32 palette_address = address; \ - address16(palette_ram, palette_address) = value; \ + address16(palette_ram, palette_address) = eswap16(value); \ convert_palette(value); \ address16(palette_ram_converted, palette_address) = value; \ } \ @@ -1483,11 +1479,11 @@ cpu_alert_type function_cc write_io_register32(u32 address, u32 value) u32 palette_address = address; \ u32 value_high = value >> 16; \ u32 value_low = value & 0xFFFF; \ - address32(palette_ram, palette_address) = value; \ + address32(palette_ram, palette_address) = eswap32(value); \ convert_palette(value_high); \ + address16(palette_ram_converted, palette_address + 2) = value_high; \ convert_palette(value_low); \ - value = (value_high << 16) | value_low; \ - address32(palette_ram_converted, palette_address) = value; \ + address16(palette_ram_converted, palette_address) = value_low; \ } \ @@ -1621,13 +1617,13 @@ void function_cc write_backup(u32 address, u32 value) #define write_vram8() \ address &= ~0x01; \ - address16(vram, address) = ((value << 8) | value) \ + address16(vram, address) = eswap16((value << 8) | value) \ #define write_vram16() \ - address16(vram, address) = value \ + address16(vram, address) = eswap16(value) \ #define write_vram32() \ - address32(vram, address) = value \ + address32(vram, address) = eswap32(value) \ // RTC code derived from VBA's (due to lack of any real publically available // documentation...) @@ -1687,7 +1683,7 @@ static u32 encode_bcd(u8 value) if(!map) \ map = load_gamepak_page(rtc_page_index & 0x3FF); \ \ - address16(map, update_address & 0x7FFF) = _value \ + address16(map, update_address & 0x7FFF) = eswap16(_value) \ void function_cc write_rtc(u32 address, u32 value) { @@ -1902,12 +1898,12 @@ void function_cc write_rtc(u32 address, u32 value) { \ case 0x02: \ /* external work RAM */ \ - address##type(ewram, (address & 0x3FFFF)) = value; \ + address##type(ewram, (address & 0x3FFFF)) = eswap##type(value); \ break; \ \ case 0x03: \ /* internal work RAM */ \ - address##type(iwram, (address & 0x7FFF) + 0x8000) = value; \ + address##type(iwram, (address & 0x7FFF) + 0x8000) = eswap##type(value); \ break; \ \ case 0x04: \ @@ -1931,7 +1927,7 @@ void function_cc write_rtc(u32 address, u32 value) case 0x07: \ /* OAM RAM */ \ reg[OAM_UPDATED] = 1; \ - address##type(oam_ram, address & 0x3FF) = value; \ + address##type(oam_ram, address & 0x3FF) = eswap##type(value); \ break; \ \ case 0x08: \ @@ -2384,7 +2380,6 @@ u32 load_gamepak(const char *name) { char *dot_position = strrchr(name, '.'); s32 file_size; - char cheats_filename[256]; char *p; if(!strcmp(dot_position, ".zip")) @@ -2430,9 +2425,6 @@ u32 load_gamepak(const char *name) if ((load_game_config_over(gamepak_title, gamepak_code, gamepak_maker)) == -1) load_game_config(gamepak_title, gamepak_code, gamepak_maker); - change_ext(gamepak_filename, cheats_filename, ".cht"); - add_cheats(cheats_filename); - return 0; } @@ -2500,19 +2492,6 @@ dma_region_type dma_region_map[16] = DMA_REGION_EXT // 0x0F - gamepak SRAM/flash ROM }; -#define dma_adjust_ptr_inc(ptr, size) \ - ptr += (size / 8) \ - -#define dma_adjust_ptr_dec(ptr, size) \ - ptr -= (size / 8) \ - -#define dma_adjust_ptr_fix(ptr, size) \ - -#define dma_adjust_ptr_writeback() \ - dma->dest_address = dest_ptr \ - -#define dma_adjust_ptr_reload() \ - #define dma_print(src_op, dest_op, transfer_size, wb) \ printf("dma from %x (%s) to %x (%s) for %x (%s) (%s) (%d) (pc %x)\n", \ src_ptr, #src_op, dest_ptr, #dest_op, length, #transfer_size, #wb, \ @@ -2571,26 +2550,26 @@ dma_region_type dma_region_map[16] = } \ #define dma_read_iwram(type, transfer_size) \ - read_value = address##transfer_size(iwram + 0x8000, type##_ptr & 0x7FFF) \ + read_value = readaddress##transfer_size(iwram + 0x8000, type##_ptr & 0x7FFF)\ #define dma_read_vram(type, transfer_size) \ - read_value = address##transfer_size(vram, type##_ptr & 0x1FFFF) \ + read_value = readaddress##transfer_size(vram, type##_ptr & 0x1FFFF) \ #define dma_read_io(type, transfer_size) \ - read_value = address##transfer_size(io_registers, type##_ptr & 0x7FFF) \ + read_value = readaddress##transfer_size(io_registers, type##_ptr & 0x7FFF) \ #define dma_read_oam_ram(type, transfer_size) \ - read_value = address##transfer_size(oam_ram, type##_ptr & 0x3FF) \ + read_value = readaddress##transfer_size(oam_ram, type##_ptr & 0x3FF) \ #define dma_read_palette_ram(type, transfer_size) \ - read_value = address##transfer_size(palette_ram, type##_ptr & 0x3FF) \ + read_value = readaddress##transfer_size(palette_ram, type##_ptr & 0x3FF) \ #define dma_read_ewram(type, transfer_size) \ - read_value = address##transfer_size(ewram, type##_ptr & 0x3FFFF) \ + read_value = readaddress##transfer_size(ewram, type##_ptr & 0x3FFFF) \ #define dma_read_gamepak(type, transfer_size) \ dma_gamepak_check_region(type); \ - read_value = address##transfer_size(type##_address_block, \ + read_value = readaddress##transfer_size(type##_address_block, \ type##_ptr & 0x7FFF) \ // DMAing from the BIOS is funny, just returns 0.. @@ -2602,17 +2581,20 @@ dma_region_type dma_region_map[16] = read_value = read_memory##transfer_size(type##_ptr) \ #define dma_write_iwram(type, transfer_size) \ - address##transfer_size(iwram + 0x8000, type##_ptr & 0x7FFF) = read_value; \ + address##transfer_size(iwram + 0x8000, type##_ptr & 0x7FFF) = \ + eswap##transfer_size(read_value); \ smc_trigger |= address##transfer_size(iwram, type##_ptr & 0x7FFF) \ #define dma_write_vram(type, transfer_size) \ - address##transfer_size(vram, type##_ptr & 0x1FFFF) = read_value \ + address##transfer_size(vram, type##_ptr & 0x1FFFF) = \ + eswap##transfer_size(read_value) \ #define dma_write_io(type, transfer_size) \ write_io_register##transfer_size(type##_ptr & 0x3FF, read_value) \ #define dma_write_oam_ram(type, transfer_size) \ - address##transfer_size(oam_ram, type##_ptr & 0x3FF) = read_value \ + address##transfer_size(oam_ram, type##_ptr & 0x3FF) = \ + eswap##transfer_size(read_value) \ #define dma_write_palette_ram(type, transfer_size) \ write_palette##transfer_size(type##_ptr & 0x3FF, read_value) \ @@ -2621,7 +2603,8 @@ dma_region_type dma_region_map[16] = write_memory##transfer_size(type##_ptr, read_value) \ #define dma_write_ewram(type, transfer_size) \ - address##transfer_size(ewram, type##_ptr & 0x3FFFF) = read_value; \ + address##transfer_size(ewram, type##_ptr & 0x3FFFF) = \ + eswap##transfer_size(read_value); \ smc_trigger |= address##transfer_size(ewram, \ (type##_ptr & 0x3FFFF) + 0x40000) \ @@ -2664,17 +2647,24 @@ dma_region_type dma_region_map[16] = { \ dma_read_##src_region_type(src, transfer_size); \ dma_write_##dest_region_type(dest, transfer_size); \ - dma_adjust_ptr_##src_op(src_ptr, transfer_size); \ - dma_adjust_ptr_##dest_op(dest_ptr, transfer_size); \ + src_ptr += src_op; \ + dest_ptr += dest_op; \ } \ dma->source_address = src_ptr; \ - dma_adjust_ptr_##wb(); \ + if (wb) \ + dma->dest_address = dest_ptr; \ dma_epilogue_##dest_region_type(); \ break; \ } \ -#define dma_transfer_loop(src_op, dest_op, transfer_size, wb); \ +#define dma_tf_loop_builder(transfer_size) \ +cpu_alert_type dma_tf_loop##transfer_size( \ + u32 src_ptr, u32 dest_ptr, int src_strd, int dest_strd, \ + bool wb, u32 length, dma_transfer_type *dma) \ { \ + u32 i; \ + u32 read_value; \ + cpu_alert_type return_value = CPU_ALERT_NONE; \ u32 src_region = src_ptr >> 24; \ u32 dest_region = dest_ptr >> 24; \ dma_region_type src_region_type = dma_region_map[src_region]; \ @@ -2683,268 +2673,269 @@ dma_region_type dma_region_map[16] = switch(src_region_type | (dest_region_type << 4)) \ { \ case (DMA_REGION_BIOS | (DMA_REGION_IWRAM << 4)): \ - dma_transfer_loop_region(bios, iwram, src_op, dest_op, \ + dma_transfer_loop_region(bios, iwram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IWRAM | (DMA_REGION_IWRAM << 4)): \ - dma_transfer_loop_region(iwram, iwram, src_op, dest_op, \ + dma_transfer_loop_region(iwram, iwram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EWRAM | (DMA_REGION_IWRAM << 4)): \ - dma_transfer_loop_region(ewram, iwram, src_op, dest_op, \ + dma_transfer_loop_region(ewram, iwram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_VRAM | (DMA_REGION_IWRAM << 4)): \ - dma_transfer_loop_region(vram, iwram, src_op, dest_op, \ + dma_transfer_loop_region(vram, iwram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_PALETTE_RAM | (DMA_REGION_IWRAM << 4)): \ - dma_transfer_loop_region(palette_ram, iwram, src_op, dest_op, \ + dma_transfer_loop_region(palette_ram, iwram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_OAM_RAM | (DMA_REGION_IWRAM << 4)): \ - dma_transfer_loop_region(oam_ram, iwram, src_op, dest_op, \ + dma_transfer_loop_region(oam_ram, iwram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IO | (DMA_REGION_IWRAM << 4)): \ - dma_transfer_loop_region(io, iwram, src_op, dest_op, \ + dma_transfer_loop_region(io, iwram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_GAMEPAK | (DMA_REGION_IWRAM << 4)): \ - dma_transfer_loop_region(gamepak, iwram, src_op, dest_op, \ + dma_transfer_loop_region(gamepak, iwram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EXT | (DMA_REGION_IWRAM << 4)): \ - dma_transfer_loop_region(ext, iwram, src_op, dest_op, \ + dma_transfer_loop_region(ext, iwram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_BIOS | (DMA_REGION_EWRAM << 4)): \ - dma_transfer_loop_region(bios, ewram, src_op, dest_op, \ + dma_transfer_loop_region(bios, ewram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IWRAM | (DMA_REGION_EWRAM << 4)): \ - dma_transfer_loop_region(iwram, ewram, src_op, dest_op, \ + dma_transfer_loop_region(iwram, ewram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EWRAM | (DMA_REGION_EWRAM << 4)): \ - dma_transfer_loop_region(ewram, ewram, src_op, dest_op, \ + dma_transfer_loop_region(ewram, ewram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_VRAM | (DMA_REGION_EWRAM << 4)): \ - dma_transfer_loop_region(vram, ewram, src_op, dest_op, \ + dma_transfer_loop_region(vram, ewram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_PALETTE_RAM | (DMA_REGION_EWRAM << 4)): \ - dma_transfer_loop_region(palette_ram, ewram, src_op, dest_op, \ + dma_transfer_loop_region(palette_ram, ewram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_OAM_RAM | (DMA_REGION_EWRAM << 4)): \ - dma_transfer_loop_region(oam_ram, ewram, src_op, dest_op, \ + dma_transfer_loop_region(oam_ram, ewram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IO | (DMA_REGION_EWRAM << 4)): \ - dma_transfer_loop_region(io, ewram, src_op, dest_op, \ + dma_transfer_loop_region(io, ewram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_GAMEPAK | (DMA_REGION_EWRAM << 4)): \ - dma_transfer_loop_region(gamepak, ewram, src_op, dest_op, \ + dma_transfer_loop_region(gamepak, ewram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EXT | (DMA_REGION_EWRAM << 4)): \ - dma_transfer_loop_region(ext, ewram, src_op, dest_op, \ + dma_transfer_loop_region(ext, ewram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_BIOS | (DMA_REGION_VRAM << 4)): \ - dma_transfer_loop_region(bios, vram, src_op, dest_op, \ + dma_transfer_loop_region(bios, vram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IWRAM | (DMA_REGION_VRAM << 4)): \ - dma_transfer_loop_region(iwram, vram, src_op, dest_op, \ + dma_transfer_loop_region(iwram, vram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EWRAM | (DMA_REGION_VRAM << 4)): \ - dma_transfer_loop_region(ewram, vram, src_op, dest_op, \ + dma_transfer_loop_region(ewram, vram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_VRAM | (DMA_REGION_VRAM << 4)): \ - dma_transfer_loop_region(vram, vram, src_op, dest_op, \ + dma_transfer_loop_region(vram, vram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_PALETTE_RAM | (DMA_REGION_VRAM << 4)): \ - dma_transfer_loop_region(palette_ram, vram, src_op, dest_op, \ + dma_transfer_loop_region(palette_ram, vram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_OAM_RAM | (DMA_REGION_VRAM << 4)): \ - dma_transfer_loop_region(oam_ram, vram, src_op, dest_op, \ + dma_transfer_loop_region(oam_ram, vram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IO | (DMA_REGION_VRAM << 4)): \ - dma_transfer_loop_region(io, vram, src_op, dest_op, \ + dma_transfer_loop_region(io, vram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_GAMEPAK | (DMA_REGION_VRAM << 4)): \ - dma_transfer_loop_region(gamepak, vram, src_op, dest_op, \ + dma_transfer_loop_region(gamepak, vram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EXT | (DMA_REGION_VRAM << 4)): \ - dma_transfer_loop_region(ext, vram, src_op, dest_op, \ + dma_transfer_loop_region(ext, vram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_BIOS | (DMA_REGION_PALETTE_RAM << 4)): \ - dma_transfer_loop_region(bios, palette_ram, src_op, dest_op, \ + dma_transfer_loop_region(bios, palette_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IWRAM | (DMA_REGION_PALETTE_RAM << 4)): \ - dma_transfer_loop_region(iwram, palette_ram, src_op, dest_op, \ + dma_transfer_loop_region(iwram, palette_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EWRAM | (DMA_REGION_PALETTE_RAM << 4)): \ - dma_transfer_loop_region(ewram, palette_ram, src_op, dest_op, \ + dma_transfer_loop_region(ewram, palette_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_VRAM | (DMA_REGION_PALETTE_RAM << 4)): \ - dma_transfer_loop_region(vram, palette_ram, src_op, dest_op, \ + dma_transfer_loop_region(vram, palette_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_PALETTE_RAM | (DMA_REGION_PALETTE_RAM << 4)): \ - dma_transfer_loop_region(palette_ram, palette_ram, src_op, dest_op, \ + dma_transfer_loop_region(palette_ram, palette_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_OAM_RAM | (DMA_REGION_PALETTE_RAM << 4)): \ - dma_transfer_loop_region(oam_ram, palette_ram, src_op, dest_op, \ + dma_transfer_loop_region(oam_ram, palette_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IO | (DMA_REGION_PALETTE_RAM << 4)): \ - dma_transfer_loop_region(io, palette_ram, src_op, dest_op, \ + dma_transfer_loop_region(io, palette_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_GAMEPAK | (DMA_REGION_PALETTE_RAM << 4)): \ - dma_transfer_loop_region(gamepak, palette_ram, src_op, dest_op, \ + dma_transfer_loop_region(gamepak, palette_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EXT | (DMA_REGION_PALETTE_RAM << 4)): \ - dma_transfer_loop_region(ext, palette_ram, src_op, dest_op, \ + dma_transfer_loop_region(ext, palette_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_BIOS | (DMA_REGION_OAM_RAM << 4)): \ - dma_transfer_loop_region(bios, oam_ram, src_op, dest_op, \ + dma_transfer_loop_region(bios, oam_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IWRAM | (DMA_REGION_OAM_RAM << 4)): \ - dma_transfer_loop_region(iwram, oam_ram, src_op, dest_op, \ + dma_transfer_loop_region(iwram, oam_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EWRAM | (DMA_REGION_OAM_RAM << 4)): \ - dma_transfer_loop_region(ewram, oam_ram, src_op, dest_op, \ + dma_transfer_loop_region(ewram, oam_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_VRAM | (DMA_REGION_OAM_RAM << 4)): \ - dma_transfer_loop_region(vram, oam_ram, src_op, dest_op, \ + dma_transfer_loop_region(vram, oam_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_PALETTE_RAM | (DMA_REGION_OAM_RAM << 4)): \ - dma_transfer_loop_region(palette_ram, oam_ram, src_op, dest_op, \ + dma_transfer_loop_region(palette_ram, oam_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_OAM_RAM | (DMA_REGION_OAM_RAM << 4)): \ - dma_transfer_loop_region(oam_ram, oam_ram, src_op, dest_op, \ + dma_transfer_loop_region(oam_ram, oam_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IO | (DMA_REGION_OAM_RAM << 4)): \ - dma_transfer_loop_region(io, oam_ram, src_op, dest_op, \ + dma_transfer_loop_region(io, oam_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_GAMEPAK | (DMA_REGION_OAM_RAM << 4)): \ - dma_transfer_loop_region(gamepak, oam_ram, src_op, dest_op, \ + dma_transfer_loop_region(gamepak, oam_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EXT | (DMA_REGION_OAM_RAM << 4)): \ - dma_transfer_loop_region(ext, oam_ram, src_op, dest_op, \ + dma_transfer_loop_region(ext, oam_ram, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_BIOS | (DMA_REGION_IO << 4)): \ - dma_transfer_loop_region(bios, io, src_op, dest_op, \ + dma_transfer_loop_region(bios, io, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IWRAM | (DMA_REGION_IO << 4)): \ - dma_transfer_loop_region(iwram, io, src_op, dest_op, \ + dma_transfer_loop_region(iwram, io, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EWRAM | (DMA_REGION_IO << 4)): \ - dma_transfer_loop_region(ewram, io, src_op, dest_op, \ + dma_transfer_loop_region(ewram, io, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_VRAM | (DMA_REGION_IO << 4)): \ - dma_transfer_loop_region(vram, io, src_op, dest_op, \ + dma_transfer_loop_region(vram, io, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_PALETTE_RAM | (DMA_REGION_IO << 4)): \ - dma_transfer_loop_region(palette_ram, io, src_op, dest_op, \ + dma_transfer_loop_region(palette_ram, io, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_OAM_RAM | (DMA_REGION_IO << 4)): \ - dma_transfer_loop_region(oam_ram, io, src_op, dest_op, \ + dma_transfer_loop_region(oam_ram, io, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IO | (DMA_REGION_IO << 4)): \ - dma_transfer_loop_region(io, io, src_op, dest_op, \ + dma_transfer_loop_region(io, io, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_GAMEPAK | (DMA_REGION_IO << 4)): \ - dma_transfer_loop_region(gamepak, io, src_op, dest_op, \ + dma_transfer_loop_region(gamepak, io, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EXT | (DMA_REGION_IO << 4)): \ - dma_transfer_loop_region(ext, io, src_op, dest_op, \ + dma_transfer_loop_region(ext, io, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_BIOS | (DMA_REGION_EXT << 4)): \ - dma_transfer_loop_region(bios, ext, src_op, dest_op, \ + dma_transfer_loop_region(bios, ext, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IWRAM | (DMA_REGION_EXT << 4)): \ - dma_transfer_loop_region(iwram, ext, src_op, dest_op, \ + dma_transfer_loop_region(iwram, ext, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EWRAM | (DMA_REGION_EXT << 4)): \ - dma_transfer_loop_region(ewram, ext, src_op, dest_op, \ + dma_transfer_loop_region(ewram, ext, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_VRAM | (DMA_REGION_EXT << 4)): \ - dma_transfer_loop_region(vram, ext, src_op, dest_op, \ + dma_transfer_loop_region(vram, ext, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_PALETTE_RAM | (DMA_REGION_EXT << 4)): \ - dma_transfer_loop_region(palette_ram, ext, src_op, dest_op, \ + dma_transfer_loop_region(palette_ram, ext, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_OAM_RAM | (DMA_REGION_EXT << 4)): \ - dma_transfer_loop_region(oam_ram, ext, src_op, dest_op, \ + dma_transfer_loop_region(oam_ram, ext, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_IO | (DMA_REGION_EXT << 4)): \ - dma_transfer_loop_region(io, ext, src_op, dest_op, \ + dma_transfer_loop_region(io, ext, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_GAMEPAK | (DMA_REGION_EXT << 4)): \ - dma_transfer_loop_region(gamepak, ext, src_op, dest_op, \ + dma_transfer_loop_region(gamepak, ext, src_strd, dest_strd, \ transfer_size, wb); \ \ case (DMA_REGION_EXT | (DMA_REGION_EXT << 3)): \ - dma_transfer_loop_region(ext, ext, src_op, dest_op, \ + dma_transfer_loop_region(ext, ext, src_strd, dest_strd, \ transfer_size, wb); \ } \ - break; \ + return return_value; \ } \ +dma_tf_loop_builder(16); +dma_tf_loop_builder(32); + cpu_alert_type dma_transfer(dma_transfer_type *dma) { - u32 i; u32 length = dma->length; - u32 read_value; u32 src_ptr = dma->source_address; uintptr_t dest_ptr = dma->dest_address; - cpu_alert_type return_value = CPU_ALERT_NONE; + cpu_alert_type ret = CPU_ALERT_NONE; // Technically this should be done for source and destination, but // chances are this is only ever used (probably mistakingly!) for dest. @@ -2973,35 +2964,35 @@ cpu_alert_type dma_transfer(dma_transfer_type *dma) switch((dma->dest_direction << 2) | dma->source_direction) { case 0x00: - dma_transfer_loop(inc, inc, 16, writeback); + ret = dma_tf_loop16(src_ptr, dest_ptr, 2, 2, true, length, dma); break; case 0x01: - dma_transfer_loop(dec, inc, 16, writeback); + ret = dma_tf_loop16(src_ptr, dest_ptr, -2, 2, true, length, dma); break; case 0x02: - dma_transfer_loop(fix, inc, 16, writeback); + ret = dma_tf_loop16(src_ptr, dest_ptr, 0, 2, true, length, dma); break; case 0x03: break; case 0x04: - dma_transfer_loop(inc, dec, 16, writeback); + ret = dma_tf_loop16(src_ptr, dest_ptr, 2, -2, true, length, dma); break; case 0x05: - dma_transfer_loop(dec, dec, 16, writeback); + ret = dma_tf_loop16(src_ptr, dest_ptr, -2, -2, true, length, dma); break; case 0x06: - dma_transfer_loop(fix, dec, 16, writeback); + ret = dma_tf_loop16(src_ptr, dest_ptr, 0, -2, true, length, dma); break; case 0x07: break; case 0x08: - dma_transfer_loop(inc, fix, 16, writeback); + ret = dma_tf_loop16(src_ptr, dest_ptr, 2, 0, true, length, dma); break; case 0x09: - dma_transfer_loop(dec, fix, 16, writeback); + ret = dma_tf_loop16(src_ptr, dest_ptr, -2, 0, true, length, dma); break; case 0x0A: - dma_transfer_loop(fix, fix, 16, writeback); + ret = dma_tf_loop16(src_ptr, dest_ptr, 0, 0, true, length, dma); break; case 0x0B: break; case 0x0C: - dma_transfer_loop(inc, inc, 16, reload); + ret = dma_tf_loop16(src_ptr, dest_ptr, 2, 2, false, length, dma); break; case 0x0D: - dma_transfer_loop(dec, inc, 16, reload); + ret = dma_tf_loop16(src_ptr, dest_ptr, -2, 2, false, length, dma); break; case 0x0E: - dma_transfer_loop(fix, inc, 16, reload); + ret = dma_tf_loop16(src_ptr, dest_ptr, 0, 2, false, length, dma); break; case 0x0F: break; } @@ -3015,35 +3006,35 @@ cpu_alert_type dma_transfer(dma_transfer_type *dma) switch((dma->dest_direction << 2) | dma->source_direction) { case 0x00: - dma_transfer_loop(inc, inc, 32, writeback); + ret = dma_tf_loop32(src_ptr, dest_ptr, 4, 4, true, length, dma); break; case 0x01: - dma_transfer_loop(dec, inc, 32, writeback); + ret = dma_tf_loop32(src_ptr, dest_ptr, -4, 4, true, length, dma); break; case 0x02: - dma_transfer_loop(fix, inc, 32, writeback); + ret = dma_tf_loop32(src_ptr, dest_ptr, 0, 4, true, length, dma); break; case 0x03: break; case 0x04: - dma_transfer_loop(inc, dec, 32, writeback); + ret = dma_tf_loop32(src_ptr, dest_ptr, 4, -4, true, length, dma); break; case 0x05: - dma_transfer_loop(dec, dec, 32, writeback); + ret = dma_tf_loop32(src_ptr, dest_ptr, -4, -4, true, length, dma); break; case 0x06: - dma_transfer_loop(fix, dec, 32, writeback); + ret = dma_tf_loop32(src_ptr, dest_ptr, 0, -4, true, length, dma); break; case 0x07: break; case 0x08: - dma_transfer_loop(inc, fix, 32, writeback); + ret = dma_tf_loop32(src_ptr, dest_ptr, 4, 0, true, length, dma); break; case 0x09: - dma_transfer_loop(dec, fix, 32, writeback); + ret = dma_tf_loop32(src_ptr, dest_ptr, -4, 0, true, length, dma); break; case 0x0A: - dma_transfer_loop(fix, fix, 32, writeback); + ret = dma_tf_loop32(src_ptr, dest_ptr, 0, 0, true, length, dma); break; case 0x0B: break; case 0x0C: - dma_transfer_loop(inc, inc, 32, reload); + ret = dma_tf_loop32(src_ptr, dest_ptr, 4, 4, false, length, dma); break; case 0x0D: - dma_transfer_loop(dec, inc, 32, reload); + ret = dma_tf_loop32(src_ptr, dest_ptr, -4, 4, false, length, dma); break; case 0x0E: - dma_transfer_loop(fix, inc, 32, reload); + ret = dma_tf_loop32(src_ptr, dest_ptr, 0, 4, false, length, dma); break; case 0x0F: break; } @@ -3053,17 +3044,17 @@ cpu_alert_type dma_transfer(dma_transfer_type *dma) (dma->start_type == DMA_START_IMMEDIATELY)) { dma->start_type = DMA_INACTIVE; - address16(io_registers, (dma->dma_channel * 12) + 0xBA) &= - (~0x8000); + address16(io_registers, (dma->dma_channel * 12) + 0xBA) = + readaddress16(io_registers, (dma->dma_channel * 12) + 0xBA) & (~0x8000); } if(dma->irq) { raise_interrupt(IRQ_DMA0 << dma->dma_channel); - return_value = CPU_ALERT_IRQ; + ret = CPU_ALERT_IRQ; } - return return_value; + return ret; } // Be sure to do this after loading ROMs. @@ -3166,12 +3157,12 @@ static void init_memory_gamepak(void) } else { - map_region(read, 0x8000000, 0x8000000 + gamepak_size, 1024, gamepak_rom); - map_null(read, 0x8000000 + gamepak_size, 0xA000000); - map_region(read, 0xA000000, 0xA000000 + gamepak_size, 1024, gamepak_rom); - map_null(read, 0xA000000 + gamepak_size, 0xC000000); - map_region(read, 0xC000000, 0xC000000 + gamepak_size, 1024, gamepak_rom); - map_null(read, 0xC000000 + gamepak_size, 0xE000000); + /* Map the ROM using mirroring, not many games use it */ + unsigned numblocks = gamepak_size >> 15; + map_region(read, 0x8000000, 0xA000000, numblocks, gamepak_rom); + map_region(read, 0xA000000, 0xC000000, numblocks, gamepak_rom); + map_region(read, 0xC000000, 0xD000000, numblocks, gamepak_rom); + /* Do not map D-E regions since they are also used for FLASH */ } } @@ -3207,38 +3198,6 @@ void init_memory(void) { u32 map_offset = 0; - memory_regions[0x00] = (u8 *)bios_rom; - memory_regions[0x01] = (u8 *)bios_rom; - memory_regions[0x02] = (u8 *)ewram; - memory_regions[0x03] = (u8 *)iwram + 0x8000; - memory_regions[0x04] = (u8 *)io_registers; - memory_regions[0x05] = (u8 *)palette_ram; - memory_regions[0x06] = (u8 *)vram; - memory_regions[0x07] = (u8 *)oam_ram; - memory_regions[0x08] = (u8 *)gamepak_rom; - memory_regions[0x09] = (u8 *)(gamepak_rom + 0xFFFFFF); - memory_regions[0x0A] = (u8 *)gamepak_rom; - memory_regions[0x0B] = (u8 *)(gamepak_rom + 0xFFFFFF); - memory_regions[0x0C] = (u8 *)gamepak_rom; - memory_regions[0x0D] = (u8 *)(gamepak_rom + 0xFFFFFF); - memory_regions[0x0E] = (u8 *)gamepak_backup; - - memory_limits[0x00] = 0x3FFF; - memory_limits[0x01] = 0x3FFF; - memory_limits[0x02] = 0x3FFFF; - memory_limits[0x03] = 0x7FFF; - memory_limits[0x04] = 0x7FFF; - memory_limits[0x05] = 0x3FF; - memory_limits[0x06] = 0x17FFF; - memory_limits[0x07] = 0x3FF; - memory_limits[0x08] = 0x1FFFFFF; - memory_limits[0x09] = 0x1FFFFFF; - memory_limits[0x0A] = 0x1FFFFFF; - memory_limits[0x0B] = 0x1FFFFFF; - memory_limits[0x0C] = 0x1FFFFFF; - memory_limits[0x0D] = 0x1FFFFFF; - memory_limits[0x0E] = 0xFFFF; - // Fill memory map regions, areas marked as NULL must be checked directly map_region(read, 0x0000000, 0x1000000, 1, bios_rom); map_null(read, 0x1000000, 0x2000000); @@ -3259,13 +3218,13 @@ void init_memory(void) memset(ewram, 0, sizeof(ewram)); memset(vram, 0, sizeof(vram)); - io_registers[REG_DISPCNT] = 0x80; - io_registers[REG_P1] = 0x3FF; - io_registers[REG_BG2PA] = 0x100; - io_registers[REG_BG2PD] = 0x100; - io_registers[REG_BG3PA] = 0x100; - io_registers[REG_BG3PD] = 0x100; - io_registers[REG_RCNT] = 0x8000; + write_ioreg(REG_DISPCNT, 0x80); + write_ioreg(REG_P1, 0x3FF); + write_ioreg(REG_BG2PA, 0x100); + write_ioreg(REG_BG2PD, 0x100); + write_ioreg(REG_BG3PA, 0x100); + write_ioreg(REG_BG3PD, 0x100); + write_ioreg(REG_RCNT, 0x8000); backup_type = BACKUP_NONE; diff --git a/gba_memory.h b/gba_memory.h index 3163bfb..7e5141f 100644 --- a/gba_memory.h +++ b/gba_memory.h @@ -122,6 +122,19 @@ typedef enum REG_BLDCNT = 0x28, REG_BLDALPHA = 0x29, REG_BLDY = 0x2A, + REG_SOUND1CNT_L = 0x30, + REG_SOUND1CNT_H = 0x31, + REG_SOUND3CNT_L = 0x38, + REG_SOUND3CNT_H = 0x39, + REG_SOUND3CNT_X = 0x3A, + REG_SOUND4CNT_H = 0x3E, + REG_SOUNDCNT_L = 0x40, + REG_SOUNDCNT_H = 0x41, + REG_SOUNDCNT_X = 0x42, + REG_DMA0SAD = 0x58, + REG_DMA0DAD = 0x5A, + REG_DMA0CNT_L = 0x5C, + REG_DMA0CNT_H = 0x5D, REG_TM0D = 0x80, REG_TM0CNT = 0x81, REG_TM1D = 0x82, @@ -171,9 +184,6 @@ u8 read_backup(u32 address); void function_cc write_backup(u32 address, u32 value); void function_cc write_rtc(u32 address, u32 value); -extern u8 *memory_regions[16]; -extern u32 memory_limits[16]; - /* EDIT: Shouldn't this be extern ?! */ extern u32 waitstate_cycles_sequential[16][3]; @@ -23,14 +23,26 @@ #include "frontend/libpicofe/input.h" #endif +bool libretro_supports_bitmasks = false; +bool libretro_supports_ff_override = false; +bool libretro_ff_enabled = false; +bool libretro_ff_enabled_prev = false; + +unsigned turbo_period = TURBO_PERIOD_MIN; +unsigned turbo_pulse_width = TURBO_PULSE_WIDTH_MIN; +unsigned turbo_a_counter = 0; +unsigned turbo_b_counter = 0; + static u32 old_key = 0; static retro_input_state_t input_state_cb; void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; } +extern void set_fastforward_override(bool fastforward); + static void trigger_key(u32 key) { - u32 p1_cnt = io_registers[REG_P1CNT]; + u32 p1_cnt = read_ioreg(REG_P1CNT); if((p1_cnt >> 14) & 0x01) { @@ -54,18 +66,74 @@ u32 update_input(void) { unsigned i; uint32_t new_key = 0; + bool turbo_a = false; + bool turbo_b = false; if (!input_state_cb) return 0; - for (i = 0; i < sizeof(btn_map) / sizeof(map); i++) - new_key |= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, btn_map[i].retropad) ? btn_map[i].gba : 0; + if (libretro_supports_bitmasks) + { + int16_t ret = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); + + for (i = 0; i < sizeof(btn_map) / sizeof(map); i++) + new_key |= (ret & (1 << btn_map[i].retropad)) ? btn_map[i].gba : 0; + + libretro_ff_enabled = libretro_supports_ff_override && + (ret & (1 << RETRO_DEVICE_ID_JOYPAD_R2)); + + turbo_a = (ret & (1 << RETRO_DEVICE_ID_JOYPAD_X)); + turbo_b = (ret & (1 << RETRO_DEVICE_ID_JOYPAD_Y)); + } + else + { + for (i = 0; i < sizeof(btn_map) / sizeof(map); i++) + new_key |= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, btn_map[i].retropad) ? btn_map[i].gba : 0; + + libretro_ff_enabled = libretro_supports_ff_override && + input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2); + + turbo_a = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X); + turbo_b = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y); + } + + /* Handle turbo buttons */ + if (turbo_a) + { + new_key |= (turbo_a_counter < turbo_pulse_width) ? + BUTTON_A : 0; + + turbo_a_counter++; + if (turbo_a_counter >= turbo_period) + turbo_a_counter = 0; + } + else + turbo_a_counter = 0; + + if (turbo_b) + { + new_key |= (turbo_b_counter < turbo_pulse_width) ? + BUTTON_B : 0; + + turbo_b_counter++; + if (turbo_b_counter >= turbo_period) + turbo_b_counter = 0; + } + else + turbo_b_counter = 0; if ((new_key | old_key) != old_key) trigger_key(new_key); old_key = new_key; - io_registers[REG_P1] = (~old_key) & 0x3FF; + write_ioreg(REG_P1, (~old_key) & 0x3FF); + + /* Handle fast forward button */ + if (libretro_ff_enabled != libretro_ff_enabled_prev) + { + set_fastforward_override(libretro_ff_enabled); + libretro_ff_enabled_prev = libretro_ff_enabled; + } return 0; } @@ -56,6 +56,23 @@ static const map btn_map[] = { { RETRO_DEVICE_ID_JOYPAD_A, BUTTON_A } }; +extern bool libretro_supports_bitmasks; +extern bool libretro_supports_ff_override; +extern bool libretro_ff_enabled; +extern bool libretro_ff_enabled_prev; + +/* Minimum (and default) turbo pulse train + * is 2 frames ON, 2 frames OFF */ +#define TURBO_PERIOD_MIN 4 +#define TURBO_PERIOD_MAX 120 +#define TURBO_PULSE_WIDTH_MIN 2 +#define TURBO_PULSE_WIDTH_MAX 15 + +extern unsigned turbo_period; +extern unsigned turbo_pulse_width; +extern unsigned turbo_a_counter; +extern unsigned turbo_b_counter; + void init_input(void); u32 update_input(void); void input_write_savestate(void); @@ -340,6 +340,31 @@ static void init_post_processing(void) /* Video post processing END */ +/* Fast forward override */ +void set_fastforward_override(bool fastforward) +{ + struct retro_fastforwarding_override ff_override; + + if (!libretro_supports_ff_override) + return; + + ff_override.ratio = -1.0f; + ff_override.notification = true; + + if (fastforward) + { + ff_override.fastforward = true; + ff_override.inhibit_toggle = true; + } + else + { + ff_override.fastforward = false; + ff_override.inhibit_toggle = false; + } + + environ_cb(RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE, &ff_override); +} + static void video_run(void) { u16 *gba_screen_pixels_buf = gba_screen_pixels; @@ -506,6 +531,14 @@ void retro_init(void) gba_screen_pixels = (uint16_t*)malloc(GBA_SCREEN_PITCH * GBA_SCREEN_HEIGHT * sizeof(uint16_t)); #endif + libretro_supports_bitmasks = false; + if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL)) + libretro_supports_bitmasks = true; + + libretro_supports_ff_override = false; + if (environ_cb(RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE, NULL)) + libretro_supports_ff_override = true; + current_frameskip_type = no_frameskip; frameskip_threshold = 0; frameskip_interval = 0; @@ -654,8 +687,32 @@ bool retro_unserialize(const void* data, size_t size) void retro_cheat_reset(void) { + cheat_clear(); +} + +void retro_cheat_set(unsigned index, bool enabled, const char* code) +{ + if (!enabled) + return; + + switch (cheat_parse(index, code)) + { + case CheatErrorTooMany: + show_warning_message("Too many active cheats!", 2500); + break; + case CheatErrorTooBig: + show_warning_message("Cheats are too big!", 2500); + break; + case CheatErrorEncrypted: + show_warning_message("Encrypted cheats are not supported!", 2500); + break; + case CheatErrorNotSupported: + show_warning_message("Cheat type is not supported!", 2500); + break; + case CheatNoError: + break; + }; } -void retro_cheat_set(unsigned index, bool enabled, const char* code) {} static void extract_directory(char* buf, const char* path, size_t size) { @@ -799,25 +856,69 @@ static void check_variables(int started_from_load) use_libretro_save_method = 0; } } + + var.key = "gpsp_turbo_period"; + var.value = NULL; + turbo_period = TURBO_PERIOD_MIN; + turbo_pulse_width = TURBO_PULSE_WIDTH_MIN; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + turbo_period = atoi(var.value); + turbo_period = (turbo_period < TURBO_PERIOD_MIN) ? + TURBO_PERIOD_MIN : turbo_period; + turbo_period = (turbo_period > TURBO_PERIOD_MAX) ? + TURBO_PERIOD_MAX : turbo_period; + + turbo_pulse_width = turbo_period >> 1; + turbo_pulse_width = (turbo_pulse_width < TURBO_PULSE_WIDTH_MIN) ? + TURBO_PULSE_WIDTH_MIN : turbo_pulse_width; + turbo_pulse_width = (turbo_pulse_width > TURBO_PULSE_WIDTH_MAX) ? + TURBO_PULSE_WIDTH_MAX : turbo_pulse_width; + + turbo_a_counter = 0; + turbo_b_counter = 0; + } } static void set_input_descriptors() { struct retro_input_descriptor descriptors[] = { - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Turbo B" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Turbo A" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, { 0 }, }; - environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, descriptors); + struct retro_input_descriptor descriptors_ff[] = { + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Turbo B" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Turbo A" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "Fast Forward" }, + { 0 }, + }; + + if (libretro_supports_ff_override) + environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, descriptors_ff); + else + environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, descriptors); } static void set_memory_descriptors(void) @@ -863,7 +964,6 @@ bool retro_load_game(const struct retro_game_info* info) strcpy(filename_bios, main_path); bool bios_loaded = false; - printf("USE %d\n", (int)selected_bios); if (selected_bios == auto_detect || selected_bios == official_bios) { bios_loaded = true; @@ -913,6 +1013,19 @@ bool retro_load_game_special(unsigned game_type, void retro_unload_game(void) { update_backup(); + + if (libretro_ff_enabled) + set_fastforward_override(false); + + libretro_supports_bitmasks = false; + libretro_supports_ff_override = false; + libretro_ff_enabled = false; + libretro_ff_enabled_prev = false; + + turbo_period = TURBO_PERIOD_MIN; + turbo_pulse_width = TURBO_PULSE_WIDTH_MIN; + turbo_a_counter = 0; + turbo_b_counter = 0; } unsigned retro_get_region(void) @@ -985,9 +1098,8 @@ void retro_run(void) { bool updated = false; - update_input(); - input_poll_cb(); + update_input(); /* Check whether current frame should * be skipped */ @@ -282,6 +282,7 @@ enum retro_language RETRO_LANGUAGE_PERSIAN = 20, RETRO_LANGUAGE_HEBREW = 21, RETRO_LANGUAGE_ASTURIAN = 22, + RETRO_LANGUAGE_FINNISH = 23, RETRO_LANGUAGE_LAST, /* Ensure sizeof(enum) == sizeof(int) */ @@ -712,6 +713,9 @@ enum retro_mod * state of rumble motors in controllers. * A strong and weak motor is supported, and they can be * controlled indepedently. + * Should be called from either retro_init() or retro_load_game(). + * Should not be called from retro_set_environment(). + * Returns false if rumble functionality is unavailable. */ #define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24 /* uint64_t * -- @@ -1374,6 +1378,121 @@ enum retro_mod * call will target the newly initialized driver. */ +#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64 + /* const struct retro_fastforwarding_override * -- + * Used by a libretro core to override the current + * fastforwarding mode of the frontend. + * If NULL is passed to this function, the frontend + * will return true if fastforwarding override + * functionality is supported (no change in + * fastforwarding state will occur in this case). + */ + +#define RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE 65 + /* const struct retro_system_content_info_override * -- + * Allows an implementation to override 'global' content + * info parameters reported by retro_get_system_info(). + * Overrides also affect subsystem content info parameters + * set via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO. + * This function must be called inside retro_set_environment(). + * If callback returns false, content info overrides + * are unsupported by the frontend, and will be ignored. + * If callback returns true, extended game info may be + * retrieved by calling RETRO_ENVIRONMENT_GET_GAME_INFO_EXT + * in retro_load_game() or retro_load_game_special(). + * + * 'data' points to an array of retro_system_content_info_override + * structs terminated by a { NULL, false, false } element. + * If 'data' is NULL, no changes will be made to the frontend; + * a core may therefore pass NULL in order to test whether + * the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and + * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks are supported + * by the frontend. + * + * For struct member descriptions, see the definition of + * struct retro_system_content_info_override. + * + * Example: + * + * - struct retro_system_info: + * { + * "My Core", // library_name + * "v1.0", // library_version + * "m3u|md|cue|iso|chd|sms|gg|sg", // valid_extensions + * true, // need_fullpath + * false // block_extract + * } + * + * - Array of struct retro_system_content_info_override: + * { + * { + * "md|sms|gg", // extensions + * false, // need_fullpath + * true // persistent_data + * }, + * { + * "sg", // extensions + * false, // need_fullpath + * false // persistent_data + * }, + * { NULL, false, false } + * } + * + * Result: + * - Files of type m3u, cue, iso, chd will not be + * loaded by the frontend. Frontend will pass a + * valid path to the core, and core will handle + * loading internally + * - Files of type md, sms, gg will be loaded by + * the frontend. A valid memory buffer will be + * passed to the core. This memory buffer will + * remain valid until retro_deinit() returns + * - Files of type sg will be loaded by the frontend. + * A valid memory buffer will be passed to the core. + * This memory buffer will remain valid until + * retro_load_game() (or retro_load_game_special()) + * returns + * + * NOTE: If an extension is listed multiple times in + * an array of retro_system_content_info_override + * structs, only the first instance will be registered + */ + +#define RETRO_ENVIRONMENT_GET_GAME_INFO_EXT 66 + /* const struct retro_game_info_ext ** -- + * Allows an implementation to fetch extended game + * information, providing additional content path + * and memory buffer status details. + * This function may only be called inside + * retro_load_game() or retro_load_game_special(). + * If callback returns false, extended game information + * is unsupported by the frontend. In this case, only + * regular retro_game_info will be available. + * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT is guaranteed + * to return true if RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE + * returns true. + * + * 'data' points to an array of retro_game_info_ext structs. + * + * For struct member descriptions, see the definition of + * struct retro_game_info_ext. + * + * - If function is called inside retro_load_game(), + * the retro_game_info_ext array is guaranteed to + * have a size of 1 - i.e. the returned pointer may + * be used to access directly the members of the + * first retro_game_info_ext struct, for example: + * + * struct retro_game_info_ext *game_info_ext; + * if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &game_info_ext)) + * printf("Content Directory: %s\n", game_info_ext->dir); + * + * - If the function is called inside retro_load_game_special(), + * the retro_game_info_ext array is guaranteed to have a + * size equal to the num_info argument passed to + * retro_load_game_special() + */ + /* VFS functionality */ /* File paths: @@ -2777,6 +2896,213 @@ struct retro_system_info bool block_extract; }; +/* Defines overrides which modify frontend handling of + * specific content file types. + * An array of retro_system_content_info_override is + * passed to RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE + * NOTE: In the following descriptions, references to + * retro_load_game() may be replaced with + * retro_load_game_special() */ +struct retro_system_content_info_override +{ + /* A list of file extensions for which the override + * should apply, delimited by a 'pipe' character + * (e.g. "md|sms|gg") + * Permitted file extensions are limited to those + * included in retro_system_info::valid_extensions + * and/or retro_subsystem_rom_info::valid_extensions */ + const char *extensions; + + /* Overrides the need_fullpath value set in + * retro_system_info and/or retro_subsystem_rom_info. + * To reiterate: + * + * If need_fullpath is true and retro_load_game() is called: + * - retro_game_info::path is guaranteed to contain a valid + * path to an existent file + * - retro_game_info::data and retro_game_info::size are invalid + * + * If need_fullpath is false and retro_load_game() is called: + * - retro_game_info::path may be NULL + * - retro_game_info::data and retro_game_info::size are guaranteed + * to be valid + * + * In addition: + * + * If need_fullpath is true and retro_load_game() is called: + * - retro_game_info_ext::full_path is guaranteed to contain a valid + * path to an existent file + * - retro_game_info_ext::archive_path may be NULL + * - retro_game_info_ext::archive_file may be NULL + * - retro_game_info_ext::dir is guaranteed to contain a valid path + * to the directory in which the content file exists + * - retro_game_info_ext::name is guaranteed to contain the + * basename of the content file, without extension + * - retro_game_info_ext::ext is guaranteed to contain the + * extension of the content file in lower case format + * - retro_game_info_ext::data and retro_game_info_ext::size + * are invalid + * + * If need_fullpath is false and retro_load_game() is called: + * - If retro_game_info_ext::file_in_archive is false: + * - retro_game_info_ext::full_path is guaranteed to contain + * a valid path to an existent file + * - retro_game_info_ext::archive_path may be NULL + * - retro_game_info_ext::archive_file may be NULL + * - retro_game_info_ext::dir is guaranteed to contain a + * valid path to the directory in which the content file exists + * - retro_game_info_ext::name is guaranteed to contain the + * basename of the content file, without extension + * - retro_game_info_ext::ext is guaranteed to contain the + * extension of the content file in lower case format + * - If retro_game_info_ext::file_in_archive is true: + * - retro_game_info_ext::full_path may be NULL + * - retro_game_info_ext::archive_path is guaranteed to + * contain a valid path to an existent compressed file + * inside which the content file is located + * - retro_game_info_ext::archive_file is guaranteed to + * contain a valid path to an existent content file + * inside the compressed file referred to by + * retro_game_info_ext::archive_path + * e.g. for a compressed file '/path/to/foo.zip' + * containing 'bar.sfc' + * > retro_game_info_ext::archive_path will be '/path/to/foo.zip' + * > retro_game_info_ext::archive_file will be 'bar.sfc' + * - retro_game_info_ext::dir is guaranteed to contain a + * valid path to the directory in which the compressed file + * (containing the content file) exists + * - retro_game_info_ext::name is guaranteed to contain + * EITHER + * 1) the basename of the compressed file (containing + * the content file), without extension + * OR + * 2) the basename of the content file inside the + * compressed file, without extension + * In either case, a core should consider 'name' to + * be the canonical name/ID of the the content file + * - retro_game_info_ext::ext is guaranteed to contain the + * extension of the content file inside the compressed file, + * in lower case format + * - retro_game_info_ext::data and retro_game_info_ext::size are + * guaranteed to be valid */ + bool need_fullpath; + + /* If need_fullpath is false, specifies whether the content + * data buffer available in retro_load_game() is 'persistent' + * + * If persistent_data is false and retro_load_game() is called: + * - retro_game_info::data and retro_game_info::size + * are valid only until retro_load_game() returns + * - retro_game_info_ext::data and retro_game_info_ext::size + * are valid only until retro_load_game() returns + * + * If persistent_data is true and retro_load_game() is called: + * - retro_game_info::data and retro_game_info::size + * are valid until retro_deinit() returns + * - retro_game_info_ext::data and retro_game_info_ext::size + * are valid until retro_deinit() returns */ + bool persistent_data; +}; + +/* Similar to retro_game_info, but provides extended + * information about the source content file and + * game memory buffer status. + * And array of retro_game_info_ext is returned by + * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT + * NOTE: In the following descriptions, references to + * retro_load_game() may be replaced with + * retro_load_game_special() */ +struct retro_game_info_ext +{ + /* - If file_in_archive is false, contains a valid + * path to an existent content file (UTF-8 encoded) + * - If file_in_archive is true, may be NULL */ + const char *full_path; + + /* - If file_in_archive is false, may be NULL + * - If file_in_archive is true, contains a valid path + * to an existent compressed file inside which the + * content file is located (UTF-8 encoded) */ + const char *archive_path; + + /* - If file_in_archive is false, may be NULL + * - If file_in_archive is true, contain a valid path + * to an existent content file inside the compressed + * file referred to by archive_path (UTF-8 encoded) + * e.g. for a compressed file '/path/to/foo.zip' + * containing 'bar.sfc' + * > archive_path will be '/path/to/foo.zip' + * > archive_file will be 'bar.sfc' */ + const char *archive_file; + + /* - If file_in_archive is false, contains a valid path + * to the directory in which the content file exists + * (UTF-8 encoded) + * - If file_in_archive is true, contains a valid path + * to the directory in which the compressed file + * (containing the content file) exists (UTF-8 encoded) */ + const char *dir; + + /* Contains the canonical name/ID of the content file + * (UTF-8 encoded). Intended for use when identifying + * 'complementary' content named after the loaded file - + * i.e. companion data of a different format (a CD image + * required by a ROM), texture packs, internally handled + * save files, etc. + * - If file_in_archive is false, contains the basename + * of the content file, without extension + * - If file_in_archive is true, then string is + * implementation specific. A frontend may choose to + * set a name value of: + * EITHER + * 1) the basename of the compressed file (containing + * the content file), without extension + * OR + * 2) the basename of the content file inside the + * compressed file, without extension + * RetroArch sets the 'name' value according to (1). + * A frontend that supports routine loading of + * content from archives containing multiple unrelated + * content files may set the 'name' value according + * to (2). */ + const char *name; + + /* - If file_in_archive is false, contains the extension + * of the content file in lower case format + * - If file_in_archive is true, contains the extension + * of the content file inside the compressed file, + * in lower case format */ + const char *ext; + + /* String of implementation specific meta-data. */ + const char *meta; + + /* Memory buffer of loaded game content. Will be NULL: + * IF + * - retro_system_info::need_fullpath is true and + * retro_system_content_info_override::need_fullpath + * is unset + * OR + * - retro_system_content_info_override::need_fullpath + * is true */ + const void *data; + + /* Size of game content memory buffer, in bytes */ + size_t size; + + /* True if loaded content file is inside a compressed + * archive */ + bool file_in_archive; + + /* - If data is NULL, value is unset/ignored + * - If data is non-NULL: + * - If persistent_data is false, data and size are + * valid only until retro_load_game() returns + * - If persistent_data is true, data and size are + * are valid until retro_deinit() returns */ + bool persistent_data; +}; + struct retro_game_geometry { unsigned base_width; /* Nominal video width of game. */ @@ -2934,6 +3260,47 @@ struct retro_framebuffer Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ }; +/* Used by a libretro core to override the current + * fastforwarding mode of the frontend */ +struct retro_fastforwarding_override +{ + /* Specifies the runtime speed multiplier that + * will be applied when 'fastforward' is true. + * For example, a value of 5.0 when running 60 FPS + * content will cap the fast-forward rate at 300 FPS. + * Note that the target multiplier may not be achieved + * if the host hardware has insufficient processing + * power. + * Setting a value of 0.0 (or greater than 0.0 but + * less than 1.0) will result in an uncapped + * fast-forward rate (limited only by hardware + * capacity). + * If the value is negative, it will be ignored + * (i.e. the frontend will use a runtime speed + * multiplier of its own choosing) */ + float ratio; + + /* If true, fastforwarding mode will be enabled. + * If false, fastforwarding mode will be disabled. */ + bool fastforward; + + /* If true, and if supported by the frontend, an + * on-screen notification will be displayed while + * 'fastforward' is true. + * If false, and if supported by the frontend, any + * on-screen fast-forward notifications will be + * suppressed */ + bool notification; + + /* If true, the core will have sole control over + * when fastforwarding mode is enabled/disabled; + * the frontend will not be able to change the + * state set by 'fastforward' until either + * 'inhibit_toggle' is set to false, or the core + * is unloaded */ + bool inhibit_toggle; +}; + /* Callbacks */ /* Environment callback. Gives implementations a way of performing diff --git a/libretro_core_options.h b/libretro_core_options.h index d2b95fa..c23a2c3 100644 --- a/libretro_core_options.h +++ b/libretro_core_options.h @@ -180,6 +180,132 @@ struct retro_core_option_definition option_defs_us[] = { "enabled" }, #endif + { + "gpsp_turbo_period", + "Turbo Button Period", + "Specify the repeat interval (in frames) when holding down the Turbo A/B buttons.", + { + { "4", NULL }, + { "5", NULL }, + { "6", NULL }, + { "7", NULL }, + { "8", NULL }, + { "9", NULL }, + { "10", NULL }, + { "11", NULL }, + { "12", NULL }, + { "13", NULL }, + { "14", NULL }, + { "15", NULL }, + { "16", NULL }, + { "17", NULL }, + { "18", NULL }, + { "19", NULL }, + { "20", NULL }, + { "21", NULL }, + { "22", NULL }, + { "23", NULL }, + { "24", NULL }, + { "25", NULL }, + { "26", NULL }, + { "27", NULL }, + { "28", NULL }, + { "29", NULL }, + { "30", NULL }, + { "31", NULL }, + { "32", NULL }, + { "33", NULL }, + { "34", NULL }, + { "35", NULL }, + { "36", NULL }, + { "37", NULL }, + { "38", NULL }, + { "39", NULL }, + { "40", NULL }, + { "41", NULL }, + { "42", NULL }, + { "43", NULL }, + { "44", NULL }, + { "45", NULL }, + { "46", NULL }, + { "47", NULL }, + { "48", NULL }, + { "49", NULL }, + { "50", NULL }, + { "51", NULL }, + { "52", NULL }, + { "53", NULL }, + { "54", NULL }, + { "55", NULL }, + { "56", NULL }, + { "57", NULL }, + { "58", NULL }, + { "59", NULL }, + { "60", NULL }, + { "61", NULL }, + { "62", NULL }, + { "63", NULL }, + { "64", NULL }, + { "65", NULL }, + { "66", NULL }, + { "67", NULL }, + { "68", NULL }, + { "69", NULL }, + { "70", NULL }, + { "71", NULL }, + { "72", NULL }, + { "73", NULL }, + { "74", NULL }, + { "75", NULL }, + { "76", NULL }, + { "77", NULL }, + { "78", NULL }, + { "79", NULL }, + { "80", NULL }, + { "81", NULL }, + { "82", NULL }, + { "83", NULL }, + { "84", NULL }, + { "85", NULL }, + { "86", NULL }, + { "87", NULL }, + { "88", NULL }, + { "89", NULL }, + { "90", NULL }, + { "91", NULL }, + { "92", NULL }, + { "93", NULL }, + { "94", NULL }, + { "95", NULL }, + { "96", NULL }, + { "97", NULL }, + { "98", NULL }, + { "99", NULL }, + { "100", NULL }, + { "101", NULL }, + { "102", NULL }, + { "103", NULL }, + { "104", NULL }, + { "105", NULL }, + { "106", NULL }, + { "107", NULL }, + { "108", NULL }, + { "109", NULL }, + { "110", NULL }, + { "111", NULL }, + { "112", NULL }, + { "113", NULL }, + { "114", NULL }, + { "115", NULL }, + { "116", NULL }, + { "117", NULL }, + { "118", NULL }, + { "119", NULL }, + { "120", NULL }, + { NULL, NULL }, + }, + "4" + }, { NULL, NULL, NULL, {{0}}, NULL }, }; @@ -63,7 +63,7 @@ static void update_timers(irq_type *irq_raised) { timer[i].count -= execute_cycles; /* io_registers accessors range: REG_TM0D, REG_TM1D, REG_TM2D, REG_TM3D */ - io_registers[128 + (i * 2)] = -(timer[i].count > timer[i].prescale); + write_ioreg(REG_TM0D + (i * 2), -(timer[i].count > timer[i].prescale)); } if(timer[i].count > 0) @@ -76,7 +76,7 @@ static void update_timers(irq_type *irq_raised) if((i != 3) && (timer[i + 1].status == TIMER_CASCADE)) { timer[i + 1].count--; - io_registers[REG_TM0D + (i + 1) * 2] = -(timer[i + 1].count); + write_ioreg(REG_TM0D + (i + 1) * 2, -timer[i+1].count); } if(i < 2) @@ -146,8 +146,8 @@ u32 update_gba(void) if(video_count <= 0) { - u32 vcount = io_registers[REG_VCOUNT]; - u32 dispstat = io_registers[REG_DISPSTAT]; + u32 vcount = read_ioreg(REG_VCOUNT); + u32 dispstat = read_ioreg(REG_DISPSTAT); if((dispstat & 0x02) == 0) { @@ -162,7 +162,7 @@ u32 update_gba(void) oam_update_count++; if(no_alpha) - io_registers[REG_BLDCNT] = 0; + write_ioreg(REG_BLDCNT, 0); update_scanline(); // If in visible area also fire HDMA @@ -196,13 +196,13 @@ u32 update_gba(void) } affine_reference_x[0] = - (s32)(address32(io_registers, 0x28) << 4) >> 4; + (s32)(readaddress32(io_registers, 0x28) << 4) >> 4; affine_reference_y[0] = - (s32)(address32(io_registers, 0x2C) << 4) >> 4; + (s32)(readaddress32(io_registers, 0x2C) << 4) >> 4; affine_reference_x[1] = - (s32)(address32(io_registers, 0x38) << 4) >> 4; + (s32)(readaddress32(io_registers, 0x38) << 4) >> 4; affine_reference_y[1] = - (s32)(address32(io_registers, 0x3C) << 4) >> 4; + (s32)(readaddress32(io_registers, 0x3C) << 4) >> 4; for(i = 0; i < 4; i++) { @@ -230,7 +230,9 @@ u32 update_gba(void) update_gbc_sound(cpu_ticks); gbc_sound_update = 0; - process_cheats(); + /* If there's no cheat hook, run on vblank! */ + if (cheat_master_hook == ~0U) + process_cheats(); vcount = 0; // We completed a frame, tell the dynarec to exit to the main thread @@ -249,9 +251,9 @@ u32 update_gba(void) else dispstat &= ~0x04; - io_registers[REG_VCOUNT] = vcount; + write_ioreg(REG_VCOUNT, vcount); } - io_registers[REG_DISPSTAT] = dispstat; + write_ioreg(REG_DISPSTAT, dispstat); } if(irq_raised) diff --git a/psp/mips_emit.h b/psp/mips_emit.h index 12685e8..7f51b8f 100644 --- a/psp/mips_emit.h +++ b/psp/mips_emit.h @@ -44,6 +44,7 @@ void mips_indirect_branch_dual(u32 address); u32 execute_read_cpsr(); u32 execute_read_spsr(); void execute_swi(u32 pc); +void mips_cheat_hook(void); u32 execute_spsr_restore(u32 address); void execute_store_cpsr(u32 new_cpsr, u32 store_mask); @@ -57,8 +58,6 @@ u32 execute_lsr_flags_reg(u32 value, u32 shift); u32 execute_asr_flags_reg(u32 value, u32 shift); u32 execute_ror_flags_reg(u32 value, u32 shift); -void reg_check(); - typedef enum { mips_reg_zero, @@ -200,18 +199,18 @@ typedef enum #define mips_emit_reg(opcode, rs, rt, rd, shift, function) \ *((u32 *)translation_ptr) = (mips_opcode_##opcode << 26) | \ - (rs << 21) | (rt << 16) | (rd << 11) | (shift << 6) | function; \ + (rs << 21) | (rt << 16) | (rd << 11) | ((shift) << 6) | function; \ translation_ptr += 4 \ #define mips_emit_special(function, rs, rt, rd, shift) \ *((u32 *)translation_ptr) = (mips_opcode_special << 26) | \ - (rs << 21) | (rt << 16) | (rd << 11) | (shift << 6) | \ + (rs << 21) | (rt << 16) | (rd << 11) | ((shift) << 6) | \ 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) | \ + (rs << 21) | (rt << 16) | (rd << 11) | ((shift) << 6) | \ mips_special2_##function; \ translation_ptr += 4 \ @@ -534,14 +533,14 @@ u32 arm_to_mips_reg[] = #define generate_load_pc(ireg, new_pc) \ { \ - s32 pc_delta = new_pc - stored_pc; \ + s32 pc_delta = (new_pc) - (stored_pc); \ if((pc_delta >= -32768) && (pc_delta <= 32767)) \ { \ mips_emit_addiu(ireg, reg_pc, pc_delta); \ } \ else \ { \ - generate_load_imm(ireg, new_pc); \ + generate_load_imm(ireg, (new_pc)); \ } \ } \ @@ -557,9 +556,6 @@ u32 arm_to_mips_reg[] = #define generate_shift_right_arithmetic(ireg, imm) \ mips_emit_sra(ireg, ireg, imm) \ -#define generate_rotate_right(ireg, imm) \ - mips_emit_rotr(ireg, ireg, imm) \ - #define generate_add(ireg_dest, ireg_src) \ mips_emit_addu(ireg_dest, ireg_dest, ireg_src) \ @@ -795,12 +791,13 @@ u32 arm_to_mips_reg[] = check_load_reg_pc(arm_reg, _rm, 8); \ if(_shift != 0) \ { \ - mips_emit_rotr(arm_to_mips_reg[arm_reg], arm_to_mips_reg[_rm], _shift); \ + rotate_right(arm_to_mips_reg[arm_reg], arm_to_mips_reg[_rm], \ + reg_temp, _shift); \ } \ else \ - { \ + { /* Special case: RRX (no carry update) */ \ mips_emit_srl(arm_to_mips_reg[arm_reg], arm_to_mips_reg[_rm], 1); \ - mips_emit_ins(arm_to_mips_reg[arm_reg], reg_c_cache, 31, 1); \ + insert_bits(arm_to_mips_reg[arm_reg], reg_c_cache, reg_temp, 31, 1); \ } \ _rm = arm_reg \ @@ -808,7 +805,7 @@ u32 arm_to_mips_reg[] = check_load_reg_pc(arm_reg, _rm, 8); \ if(_shift != 0) \ { \ - mips_emit_ext(reg_c_cache, arm_to_mips_reg[_rm], (32 - _shift), 1); \ + extract_bits(reg_c_cache, arm_to_mips_reg[_rm], (32 - _shift), 1); \ mips_emit_sll(arm_to_mips_reg[arm_reg], arm_to_mips_reg[_rm], _shift); \ _rm = arm_reg; \ } \ @@ -817,7 +814,7 @@ u32 arm_to_mips_reg[] = check_load_reg_pc(arm_reg, _rm, 8); \ if(_shift != 0) \ { \ - mips_emit_ext(reg_c_cache, arm_to_mips_reg[_rm], (_shift - 1), 1); \ + extract_bits(reg_c_cache, arm_to_mips_reg[_rm], (_shift - 1), 1); \ mips_emit_srl(arm_to_mips_reg[arm_reg], arm_to_mips_reg[_rm], _shift); \ } \ else \ @@ -831,7 +828,7 @@ u32 arm_to_mips_reg[] = check_load_reg_pc(arm_reg, _rm, 8); \ if(_shift != 0) \ { \ - mips_emit_ext(reg_c_cache, arm_to_mips_reg[_rm], (_shift - 1), 1); \ + extract_bits(reg_c_cache, arm_to_mips_reg[_rm], (_shift - 1), 1); \ mips_emit_sra(arm_to_mips_reg[arm_reg], arm_to_mips_reg[_rm], _shift); \ } \ else \ @@ -845,15 +842,16 @@ u32 arm_to_mips_reg[] = check_load_reg_pc(arm_reg, _rm, 8); \ if(_shift != 0) \ { \ - mips_emit_ext(reg_c_cache, arm_to_mips_reg[_rm], (_shift - 1), 1); \ - mips_emit_rotr(arm_to_mips_reg[arm_reg], arm_to_mips_reg[_rm], _shift); \ + extract_bits(reg_c_cache, arm_to_mips_reg[_rm], (_shift - 1), 1); \ + rotate_right(arm_to_mips_reg[arm_reg], arm_to_mips_reg[_rm], \ + reg_temp, _shift); \ } \ else \ - { \ - mips_emit_andi(reg_temp, arm_to_mips_reg[_rm], 1); \ + { /* Special case: RRX (carry update) */ \ + mips_emit_sll(reg_temp, reg_c_cache, 31); \ + mips_emit_andi(reg_c_cache, arm_to_mips_reg[_rm], 1); \ mips_emit_srl(arm_to_mips_reg[arm_reg], arm_to_mips_reg[_rm], 1); \ - mips_emit_ins(arm_to_mips_reg[arm_reg], reg_c_cache, 31, 1); \ - mips_emit_addu(reg_c_cache, reg_temp, reg_zero); \ + mips_emit_or(arm_to_mips_reg[arm_reg], arm_to_mips_reg[arm_reg],reg_temp);\ } \ _rm = arm_reg \ @@ -874,7 +872,8 @@ u32 arm_to_mips_reg[] = mips_emit_sra(reg_a0, reg_a0, 31) \ #define generate_shift_reg_ror_no_flags(_rm, _rs) \ - mips_emit_rotrv(reg_a0, arm_to_mips_reg[_rm], arm_to_mips_reg[_rs]) \ + rotate_right_var(reg_a0, arm_to_mips_reg[_rm], \ + reg_temp, arm_to_mips_reg[_rs]) \ #define generate_shift_reg_lsl_flags(_rm, _rs) \ generate_load_reg_pc(reg_a0, _rm, 12); \ @@ -896,7 +895,8 @@ u32 arm_to_mips_reg[] = mips_emit_addiu(reg_temp, arm_to_mips_reg[_rs], -1); \ mips_emit_srlv(reg_temp, arm_to_mips_reg[_rm], reg_temp); \ mips_emit_andi(reg_c_cache, reg_temp, 1); \ - mips_emit_rotrv(reg_a0, arm_to_mips_reg[_rm], arm_to_mips_reg[_rs]) \ + rotate_right_var(reg_a0, arm_to_mips_reg[_rm], \ + reg_temp, arm_to_mips_reg[_rs]) \ #define generate_shift_imm(arm_reg, name, flags_op) \ u32 shift = (opcode >> 7) & 0x1F; \ @@ -1696,6 +1696,9 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address) arm_psr_##transfer_type(op_type, psr_reg); \ } \ +#define thumb_load_pc_pool_const(rd, value) \ + generate_load_imm(arm_to_mips_reg[rd], (value)); \ + #define arm_access_memory_load(mem_type) \ cycle_count += 2; \ mips_emit_jal(mips_absolute_offset(execute_load_##mem_type)); \ @@ -1895,7 +1898,7 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address) } \ else \ { \ - mips_emit_ins(reg_a2, reg_zero, 0, 2); \ + emit_align_reg(reg_a2, 2); \ \ for(i = 0; i < 16; i++) \ { \ @@ -2071,20 +2074,6 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address) check_store_reg_pc_thumb(dest_rd); \ } \ -/* - -#define thumb_data_proc_hi(name) \ -{ \ - thumb_decode_hireg_op(); \ - check_load_reg_pc(arm_reg_a0, rs, 4); \ - check_load_reg_pc(arm_reg_a1, rd, 4); \ - generate_op_##name##_reg(arm_to_mips_reg[rd], arm_to_mips_reg[rd], \ - arm_to_mips_reg[rs]); \ - check_store_reg_pc_thumb(rd); \ -} \ - -*/ - #define thumb_data_proc_test_hi(name) \ { \ thumb_decode_hireg_op(); \ @@ -2332,7 +2321,7 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address) } \ else \ { \ - mips_emit_ins(reg_a2, reg_zero, 0, 2); \ + emit_align_reg(reg_a2, 2); \ \ for(i = 0; i < 8; i++) \ { \ @@ -2422,6 +2411,12 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address) generate_indirect_branch_cycle_update(dual); \ } \ +#define thumb_process_cheats() \ + generate_function_call(mips_cheat_hook); + +#define arm_process_cheats() \ + generate_function_call(mips_cheat_hook); + #ifdef TRACE_INSTRUCTIONS void trace_instruction(u32 pc) { @@ -2523,6 +2518,71 @@ u8 swi_hle_handle[256] = generate_load_pc(reg_a0, pc); \ mips_emit_sw(reg_a0, reg_base, (REG_PC * 4)) \ +// Some macros to wrap device-specific instructions + +/* MIPS32R2 and PSP support ins, ext, seb, rotr */ +#ifdef MIPS_HAS_R2_INSTS + // Inserts LSB bits into another register + #define insert_bits(rdest, rsrc, rtemp, pos, size) \ + mips_emit_ins(rdest, rsrc, pos, size); + // Doubles a byte into a halfword + #define double_byte(reg, rtmp) \ + mips_emit_ins(reg, reg, 8, 8); + // Clears numbits at LSB position (to align an address) + #define emit_align_reg(reg, numbits) \ + mips_emit_ins(reg, reg_zero, 0, numbits) + // Extract a bitfield (pos, size) to a register + #define extract_bits(rt, rs, pos, size) \ + mips_emit_ext(rt, rs, pos, size) + // Extends signed byte to u32 + #define extend_byte_signed(rt, rs) \ + mips_emit_seb(rt, rs) + // Rotates a word using a temp reg if necessary + #define rotate_right(rdest, rsrc, rtemp, amount) \ + mips_emit_rotr(rdest, rsrc, amount); + // Same but variable amount rotation (register) + #define rotate_right_var(rdest, rsrc, rtemp, ramount) \ + mips_emit_rotrv(rdest, rsrc, ramount); +#else + // Inserts LSB bits into another register + // *assumes dest bits are cleared*! + #define insert_bits(rdest, rsrc, rtemp, pos, size) \ + mips_emit_sll(rtemp, rsrc, 32 - size); \ + mips_emit_srl(rtemp, rtemp, 32 - size - pos); \ + mips_emit_or(rdest, rdest, rtemp); + // Doubles a byte into a halfword + #define double_byte(reg, rtmp) \ + mips_emit_sll(rtmp, reg, 8); \ + mips_emit_andi(reg, reg, 0xff); \ + mips_emit_or(reg, reg, rtmp); + // Clears numbits at LSB position (to align an address) + #define emit_align_reg(reg, numbits) \ + mips_emit_srl(reg, reg, numbits); \ + mips_emit_sll(reg, reg, numbits) + // Extract a bitfield (pos, size) to a register + #define extract_bits(rt, rs, pos, size) \ + mips_emit_sll(rt, rs, 32 - ((pos) + (size))); \ + mips_emit_srl(rt, rt, 32 - (size)) + // Extends signed byte to u32 + #define extend_byte_signed(rt, rs) \ + mips_emit_sll(rt, rs, 24); \ + mips_emit_sra(rt, rt, 24) + // Rotates a word (uses temp reg) + #define rotate_right(rdest, rsrc, rtemp, amount) \ + mips_emit_sll(rtemp, rsrc, 32 - (amount)); \ + mips_emit_srl(rdest, rsrc, (amount)); \ + mips_emit_or(rdest, rdest, rtemp) + // Variable rotation using temp reg (dst != src) + #define rotate_right_var(rdest, rsrc, rtemp, ramount) \ + mips_emit_andi(rtemp, ramount, 0x1F); \ + mips_emit_srlv(rdest, rsrc, rtemp); \ + mips_emit_subu(rtemp, reg_zero, rtemp); \ + mips_emit_addiu(rtemp, rtemp, 32); \ + mips_emit_sllv(rtemp, rsrc, rtemp); \ + mips_emit_or(rdest, rdest, rtemp) + +#endif + // Register save layout as follows: #define ReOff_RegPC (15*4) // REG_PC @@ -2563,17 +2623,18 @@ u8 swi_hle_handle[256] = emit_save_regs(true); \ genccall(fnptr); \ mips_emit_andi(reg_a0, reg_a0, (mask)); \ - emit_restore_regs(true); \ mips_emit_lw(mips_reg_ra, reg_base, ReOff_SaveR1); \ - mips_emit_jr(mips_reg_ra); + emit_restore_regs(true); #define emit_mem_call(fnptr, mask) \ emit_mem_call_ds(fnptr, mask) \ + mips_emit_jr(mips_reg_ra); \ mips_emit_nop(); // Pointer table to stubs, indexed by type and region extern u32 tmemld[11][16]; extern u32 tmemst[ 4][16]; +extern u32 thnjal[15*16]; void mips_lookup_pc(); void smc_write(); cpu_alert_type write_io_register8 (u32 address, u32 value); @@ -2692,7 +2753,7 @@ static void emit_pmemld_stub( // Address checking: jumps to handler if bad region/alignment mips_emit_srl(reg_temp, reg_a0, (32 - regionbits)); if (!aligned && size != 0) { // u8 or aligned u32 dont need to check alignment bits - mips_emit_ins(reg_temp, reg_a0, regionbits, size); // Add 1 or 2 bits of alignment + insert_bits(reg_temp, reg_a0, reg_rv, regionbits, size); // Add 1 or 2 bits of alignment } if (regioncheck || alignment) { // If region and alignment are zero, can skip mips_emit_xori(reg_temp, reg_temp, regioncheck | (alignment << regionbits)); @@ -2729,7 +2790,7 @@ static void emit_pmemld_stub( // This code call the C routine to map the relevant ROM page 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 + extract_bits(reg_a0, reg_a0, 15, 10); // a0 = (addr >> 15) & 0x3ff genccall(&load_gamepak_page); mips_emit_sw(reg_temp, reg_base, ReOff_SaveR1); @@ -2744,14 +2805,13 @@ static void emit_pmemld_stub( // Read from flash, is a bit special, fn call emit_mem_call_ds(&read_backup, 0xFFFF); if (!size && signext) { - mips_emit_seb(reg_rv, reg_rv); + extend_byte_signed(reg_rv, reg_rv); } else if (size == 1 && alignment) { - mips_emit_seb(reg_rv, reg_rv); + extend_byte_signed(reg_rv, reg_rv); } else if (size == 2) { - mips_emit_rotr(reg_rv, reg_rv, 8 * alignment); - } else { - mips_emit_nop(); + rotate_right(reg_rv, reg_rv, reg_temp, 8 * alignment); } + generate_function_return_swap_delay(); *tr_ptr = translation_ptr; return; } else { @@ -2765,21 +2825,22 @@ static void emit_pmemld_stub( if (region == 2) { // Can't do EWRAM with an `andi` instruction (18 bits mask) - mips_emit_ext(reg_a0, reg_a0, 0, 18); // &= 0x3ffff + extract_bits(reg_a0, reg_a0, 0, 18); // &= 0x3ffff if (!aligned && alignment != 0) { - mips_emit_ins(reg_a0, reg_zero, 0, size);// addr & ~1/2 (align to size) + emit_align_reg(reg_a0, size); // addr & ~1/2 (align to size) } // Need to insert a zero in the addr (due to how it's mapped) mips_emit_addu(reg_rv, reg_rv, reg_a0); // Adds to the base addr } else if (region == 6) { // VRAM is mirrored every 128KB but the last 32KB is mapped to the previous - mips_emit_ext(reg_temp, reg_a0, 15, 2); // Extract bits 15 and 16 + extract_bits(reg_temp, reg_a0, 15, 2); // Extract bits 15 and 16 mips_emit_addiu(reg_temp, reg_temp, -3); // Check for 3 (last block) if (!aligned && alignment != 0) { - mips_emit_ins(reg_a0, reg_zero, 0, size);// addr & ~1/2 (align to size) + emit_align_reg(reg_a0, size); // addr & ~1/2 (align to size) } - mips_emit_b(bne, reg_zero, reg_temp, 2); // Skip unless last block - mips_emit_ext(reg_a0, reg_a0, 0, 17); // addr & 0x1FFFF [delay] + extract_bits(reg_a0, reg_a0, 0, 17); // addr & 0x1FFFF [delay] + mips_emit_b(bne, reg_zero, reg_temp, 1); // Skip unless last block + generate_swap_delay(); mips_emit_addiu(reg_a0, reg_a0, 0x8000); // addr - 0x8000 (mirror last block) mips_emit_addu(reg_rv, reg_rv, reg_a0); // addr = base + adjusted offset } else { @@ -2790,16 +2851,13 @@ static void emit_pmemld_stub( } } - // Aligned accesses (or the weird s16u1 case) are just one inst - if (alignment == 0 || (size == 1 && signext)) { - emit_mem_access_loadop(translation_ptr, base_addr, size, alignment, signext); // Delay slot - translation_ptr += 4; - } - else { - // Unaligned accesses (require rotation) need two insts - emit_mem_access_loadop(translation_ptr, base_addr, size, alignment, signext); - translation_ptr += 4; - mips_emit_rotr(reg_rv, reg_rv, alignment * 8); // Delay slot + // Emit load operation + emit_mem_access_loadop(translation_ptr, base_addr, size, alignment, signext); + translation_ptr += 4; + + if (!(alignment == 0 || (size == 1 && signext))) { + // Unaligned accesses require rotation, except for size=1 & signext + rotate_right(reg_rv, reg_rv, reg_temp, alignment * 8); } generate_function_return_swap_delay(); // Return. Move prev inst to delay slot @@ -2837,26 +2895,27 @@ static void emit_pmemst_stub( mips_emit_lui(reg_rv, ((base_addr + 0x8000) >> 16)); if (doubleaccess) { - mips_emit_ins(reg_a1, reg_a1, 8, 8); // value = value | (value << 8) + double_byte(reg_a1, reg_temp); // value = value | (value << 8) } if (region == 2) { // Can't do EWRAM with an `andi` instruction (18 bits mask) - mips_emit_ext(reg_a0, reg_a0, 0, 18); // &= 0x3ffff + extract_bits(reg_a0, reg_a0, 0, 18); // &= 0x3ffff if (!aligned && realsize != 0) { - mips_emit_ins(reg_a0, reg_zero, 0, size);// addr & ~1/2 (align to size) + emit_align_reg(reg_a0, size); // addr & ~1/2 (align to size) } // Need to insert a zero in the addr (due to how it's mapped) mips_emit_addu(reg_rv, reg_rv, reg_a0); // Adds to the base addr } else if (region == 6) { // VRAM is mirrored every 128KB but the last 32KB is mapped to the previous - mips_emit_ext(reg_temp, reg_a0, 15, 2); // Extract bits 15 and 16 + extract_bits(reg_temp, reg_a0, 15, 2); // Extract bits 15 and 16 mips_emit_addiu(reg_temp, reg_temp, -3); // Check for 3 (last block) if (!aligned && realsize != 0) { - mips_emit_ins(reg_a0, reg_zero, 0, realsize);// addr & ~1/2 (align to size) + emit_align_reg(reg_a0, realsize); // addr & ~1/2 (align to size) } - mips_emit_b(bne, reg_zero, reg_temp, 2); // Skip unless last block - mips_emit_ext(reg_a0, reg_a0, 0, 17); // addr & 0x1FFFF [delay] + extract_bits(reg_a0, reg_a0, 0, 17); // addr & 0x1FFFF [delay] + mips_emit_b(bne, reg_zero, reg_temp, 1); // Skip next inst unless last block + generate_swap_delay(); mips_emit_addiu(reg_a0, reg_a0, 0x8000); // addr - 0x8000 (mirror last block) mips_emit_addu(reg_rv, reg_rv, reg_a0); // addr = base + adjusted offset } else { @@ -2910,19 +2969,33 @@ static void emit_pmemst_stub( *tr_ptr = translation_ptr; } +// Palette conversion functions. a1 contains the palette value (16 LSB) +// Places the result in reg_temp, can use a0 as temporary register #ifdef USE_BGR_FORMAT - /* 0BGR to BGR565, for PSP */ + /* 0BGR to BGR565, only for PSP (uses ins) */ #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); + /* 0BGR to RGB565 (clobbers a0) */ + #ifdef MIPS_HAS_R2_INSTS + #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); + #else + #define palette_convert() \ + mips_emit_srl(reg_a0, reg_a1, 10); \ + mips_emit_andi(reg_temp, reg_a0, 0x1F); \ + mips_emit_sll(reg_a0, reg_a1, 1); \ + mips_emit_andi(reg_a0, reg_a0, 0x7C0); \ + mips_emit_or(reg_temp, reg_temp, reg_a0); \ + mips_emit_andi(reg_a0, reg_a1, 0x1F); \ + mips_emit_sll(reg_a0, reg_a0, 11); \ + mips_emit_or(reg_temp, reg_temp, reg_a0); + #endif #endif // Palette is accessed differently and stored in a decoded manner @@ -2946,7 +3019,7 @@ static void emit_palette_hdl( mips_emit_b(bne, reg_zero, reg_temp, st_phndlr_branch(memop_number)); mips_emit_andi(reg_rv, reg_a0, memmask); // Clear upper bits (mirroring) if (size == 0) { - mips_emit_ins(reg_a1, reg_a1, 8, 8); // value = value | (value << 8) + double_byte(reg_a1, reg_temp); // value = value | (value << 8) } mips_emit_addu(reg_rv, reg_rv, reg_base); @@ -3177,40 +3250,41 @@ static void emit_phand( mips_emit_srl(reg_temp, reg_a0, 24); #ifdef PSP - mips_emit_addiu(reg_rv, reg_zero, 15*4); // Table limit (max) - mips_emit_sll(reg_temp, reg_temp, 2); // Table is word indexed - mips_emit_min(reg_temp, reg_temp, reg_rv);// Do not overflow table + mips_emit_addiu(reg_rv, reg_zero, 15*4); // Table limit (max) + mips_emit_sll(reg_temp, reg_temp, 2); // Table is word indexed + mips_emit_min(reg_temp, reg_temp, reg_rv);// Do not overflow table #else - mips_emit_sltiu(reg_rv, reg_temp, 0x0F); // Check for addr 0x1XXX.. 0xFXXX - mips_emit_b(bne, reg_zero, reg_rv, 2); // Skip two insts (well, cant skip ds) - mips_emit_sll(reg_temp, reg_temp, 2); // Table is word indexed - mips_emit_addiu(reg_temp, reg_zero, 15*4);// Simulate ld/st to 0x0FXXX (open/ignore) + mips_emit_sltiu(reg_rv, reg_temp, 0x0F); // Check for addr 0x1XXX.. 0xFXXX + mips_emit_sll(reg_temp, reg_temp, 2); // Table is word indexed + mips_emit_b(bne, reg_zero, reg_rv, 1); // Skip next inst if region is good + generate_swap_delay(); + mips_emit_addiu(reg_temp, reg_zero, 15*4);// Simulate ld/st to 0x0FXXX (open/ignore) #endif // Stores or byte-accesses do not care about alignment if (check_alignment) { - // Move alignment bits for the table lookup - mips_emit_ins(reg_temp, reg_a0, 6, size); // Alignment bits (1 or 2, to bits 6 (and 7) + // Move alignment bits for the table lookup (1 or 2, to bits 6 and 7) + insert_bits(reg_temp, reg_a0, reg_rv, 6, size); } unsigned tbloff = 256 + 3*1024 + 220 + 4 * toff; // Skip regs and RAMs - mips_emit_addu(reg_rv, reg_temp, reg_base); // Add to the base_reg the table offset - mips_emit_lw(reg_rv, reg_rv, tbloff); // Read addr from table - mips_emit_sll(reg_temp, reg_rv, 4); // 26 bit immediate to the MSB - mips_emit_ori(reg_temp, reg_temp, 0x3); // JAL opcode - mips_emit_rotr(reg_temp, reg_temp, 6); // Swap opcode and immediate - mips_emit_sw(reg_temp, mips_reg_ra, -8); // Patch instruction! + unsigned tbloff2 = tbloff + 960; // JAL opcode table + mips_emit_addu(reg_temp, reg_temp, reg_base); // Add to the base_reg the table offset + mips_emit_lw(reg_rv, reg_temp, tbloff); // Get func addr from 1st table + mips_emit_lw(reg_temp, reg_temp, tbloff2); // Get opcode from 2nd table + 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); + 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); + mips_emit_jr(reg_rv); + mips_emit_synci(mips_reg_ra, -8); #endif - // Round up handlers to 16 instructions for easy addressing :) + // Round up handlers to 16 instructions for easy addressing + // PSP/MIPS32r2 uses up to 12 insts while (translation_ptr - *tr_ptr < 64) { mips_emit_nop(); } @@ -3323,6 +3397,11 @@ void init_emitter() { handler(2, &stinfo[i], 2, false, &translation_ptr); // st u32 handler(3, &stinfo[i], 2, true, &translation_ptr); // st aligned 32 } + + // Generate JAL tables + u32 *tmemptr = &tmemld[0][0]; + for (i = 0; i < 15*16; i++) + thnjal[i] = ((tmemptr[i] >> 2) & 0x3FFFFFF) | (mips_opcode_jal << 26); } u32 execute_arm_translate_internal(u32 cycles, void *regptr); diff --git a/psp/mips_stub.S b/psp/mips_stub.S index 3c05f52..eb672c7 100644 --- a/psp/mips_stub.S +++ b/psp/mips_stub.S @@ -18,7 +18,19 @@ #include "../gpsp_config.h" -.set mips32r2 +// This is also defined in sys/asm.h but doesn't seem portable? +#ifdef __mips64 + .set mips64 + #define SZREG 8 + #define REG_L ld + #define REG_S sd +#else + .set mips32r2 + #define SZREG 4 + #define REG_L lw + #define REG_S sw +#endif + .align 4 .global mips_update_gba @@ -34,22 +46,19 @@ .global execute_lsl_flags_reg .global execute_lsr_flags_reg .global execute_asr_flags_reg -.global execute_ror_flags_reg .global execute_arm_translate_internal -.global icache_region_sync -.global reg_check .global palette_ram .global palette_ram_converted .global oam_ram -.global init_emitter .global mips_lookup_pc .global smc_write +.global mips_cheat_hook .global write_io_epilogue .global memory_map_read .global tmemld .global tmemst -.global tmemst +.global thnjal .global reg .global spsr .global reg_mode @@ -120,22 +129,39 @@ .equ COMPLETED_FRAME, (32 * 4) .equ OAM_UPDATED, (33 * 4) .equ GP_SAVE, (34 * 4) +.equ GP_SAVE_HI, (35 * 4) .equ SPSR_BASE, (0x100 + 0x400 * 3) .equ REGMODE_BASE, (SPSR_BASE + 24) .equ SUPERVISOR_SPSR, (3 * 4 + SPSR_BASE) .equ SUPERVISOR_LR, ((3 * (7 * 4)) + (6 * 4) + REGMODE_BASE) .equ FNPTRS_MEMOPS, (REGMODE_BASE + 196) -.equ FNPTRS_BASE, (FNPTRS_MEMOPS + 960) +.equ FNPTRS_BASE, (FNPTRS_MEMOPS + 960*2) .set noat .set noreorder # make sure $16 has the register base for these macros -.macro collapse_flag flag_reg, shift - ins $2, $\flag_reg, \shift, 1 # insert flag into CPSR -.endm +#ifdef MIPS_HAS_R2_INSTS + .macro collapse_flag flag_reg, shift + ins $2, $\flag_reg, \shift, 1 # insert flag into CPSR + .endm + + .macro extract_flag shift, flag_reg + ext $\flag_reg, $1, \shift, 1 # extract flag from CPSR + .endm +#else + .macro collapse_flag flag_reg, shift + sll $1, $\flag_reg, \shift + or $2, $2, $1 + .endm + + .macro extract_flag shift, flag_reg + srl $\flag_reg, $1, \shift + andi $\flag_reg, $\flag_reg, 1 + .endm +#endif .macro collapse_flags lw $2, REG_CPSR($16) # load CPSR @@ -147,10 +173,6 @@ sw $2, REG_CPSR($16) # store CPSR .endm -.macro extract_flag shift, flag_reg - ext $\flag_reg, $1, \shift, 1 # extract flag from CPSR -.endm - .macro extract_flags_body # extract flags from $1 extract_flag 31, 20 # load flags extract_flag 30, 21 @@ -181,7 +203,7 @@ sw $28, REG_R13($16) sw $30, REG_R14($16) - lw $28, GP_SAVE($16) + REG_L $28, GP_SAVE($16) .endm .macro restore_registers @@ -256,23 +278,33 @@ mips_update_gba: nop +# Processes cheats whenever we hit the master PC +mips_cheat_hook: + sw $ra, REG_SAVE2($16) + save_registers + cfncall process_cheats, 8 + lw $ra, REG_SAVE2($16) + restore_registers + jr $ra + nop + + # Loads the main context and returns to it. # ARM regs must be saved before branching here return_to_main: - lw $28, GP_SAVE($16) # Restore previous state - lw $s0, 0($sp) - lw $s1, 4($sp) - lw $s2, 8($sp) - lw $s3, 12($sp) - lw $s4, 16($sp) - lw $s5, 20($sp) - lw $s6, 24($sp) - lw $s7, 28($sp) - lw $fp, 32($sp) - lw $ra, 36($sp) + REG_L $28, GP_SAVE($16) # Restore previous state + REG_L $s0, 4*SZREG($sp) + REG_L $s1, 5*SZREG($sp) + REG_L $s2, 6*SZREG($sp) + REG_L $s3, 7*SZREG($sp) + REG_L $s4, 8*SZREG($sp) + REG_L $s5, 9*SZREG($sp) + REG_L $s6, 10*SZREG($sp) + REG_L $s7, 11*SZREG($sp) + REG_L $fp, 12*SZREG($sp) + REG_L $ra, 13*SZREG($sp) jr $ra # Return to main - add $sp, $sp, 48 # Restore stack pointer (delay slot) - + addiu $sp, $sp, 112 # Restore stack pointer (delay slot) # Perform an indirect branch. @@ -395,7 +427,8 @@ execute_swi: sw $4, SUPERVISOR_LR($16) # store next PC in the supervisor's LR collapse_flags # get cpsr in $2 sw $2, SUPERVISOR_SPSR($16) # save cpsr in SUPERVISOR_CPSR - ins $2, $0, 0, 6 # zero out bottom 6 bits of CPSR + srl $2, $2, 6 # zero out bottom 6 bits of CPSR + sll $2, $2, 6 ori $2, 0x13 # set mode to supervisor sw $2, REG_CPSR($16) # write back CPSR save_registers @@ -501,11 +534,11 @@ lsl_shift_high: bne $1, $0, lsl_shift_done # jump if shift == 32 andi $22, $4, 1 # c flag = value & 0x01 (delay) - add $22, $0, $0 # c flag = 0 otherwise + addu $22, $0, $0 # c flag = 0 otherwise lsl_shift_done: jr $ra # return - add $4, $0, $0 # value = 0 no matter what + addu $4, $0, $0 # value = 0 no matter what execute_lsr_flags_reg: @@ -526,11 +559,11 @@ lsr_shift_high: bne $1, $0, lsr_shift_done # jump if shift == 32 srl $22, $4, 31 # c flag = value >> 31 (delay) - add $22, $0, $0 # c flag = 0 otherwise + addu $22, $0, $0 # c flag = 0 otherwise lsr_shift_done: jr $ra # return - add $4, $0, $0 # value = 0 no matter what + addu $4, $0, $0 # value = 0 no matter what execute_asr_flags_reg: @@ -552,35 +585,25 @@ asr_shift_high: andi $22, $4, 1 # c flag = value & 0x01 -execute_ror_flags_reg: - beq $5, $0, ror_zero_shift # is the shift zero? - addiu $1, $5, -1 # $1 = (shift - 1) (delay) - - srav $1, $4, $1 # $1 = (value >> (shift - 1)) - andi $22, $1, 1 # c flag = $1 & 1 - -ror_zero_shift: - jr $ra # return - rotrv $4, $4, $5 # return (value ror shift) delay - # $4: cycle counter argument # $5: pointer to reg execute_arm_translate_internal: - add $sp, $sp, -48 # Store the main thread context - sw $s0, 0($sp) - sw $s1, 4($sp) - sw $s2, 8($sp) - sw $s3, 12($sp) - sw $s4, 16($sp) - sw $s5, 20($sp) - sw $s6, 24($sp) - sw $s7, 28($sp) - sw $fp, 32($sp) - sw $ra, 36($sp) + + addiu $sp, $sp, -112 # Store the main thread context + REG_S $s0, 4*SZREG($sp) + REG_S $s1, 5*SZREG($sp) + REG_S $s2, 6*SZREG($sp) + REG_S $s3, 7*SZREG($sp) + REG_S $s4, 8*SZREG($sp) + REG_S $s5, 9*SZREG($sp) + REG_S $s6, 10*SZREG($sp) + REG_S $s7, 11*SZREG($sp) + REG_S $fp, 12*SZREG($sp) + REG_S $ra, 13*SZREG($sp) move $16, $5 - sw $28, GP_SAVE($16) + REG_S $28, GP_SAVE($16) addu $17, $4, $0 # load cycle counter register @@ -640,6 +663,8 @@ tmemld: .space 704 tmemst: .space 256 +thnjal: + .space 960 fnptrs: .long update_gba # 0 .long block_lookup_address_arm # 1 @@ -649,6 +674,7 @@ fnptrs: .long set_cpu_mode # 5 .long execute_spsr_restore_body # 6 .long execute_store_cpsr_body # 7 + .long process_cheats # 8 #if !defined(HAVE_MMAP) @@ -90,9 +90,9 @@ void sound_timer(fixed8_24 frequency_step, u32 channel) u32 buffer_index = ds->buffer_index; s16 current_sample, next_sample; - current_sample = ds->fifo[ds->fifo_base] << 4; + current_sample = ds->fifo[ds->fifo_base] * 16; ds->fifo_base = (ds->fifo_base + 1) % 32; - next_sample = ds->fifo[ds->fifo_base] << 4; + next_sample = ds->fifo[ds->fifo_base] * 16; if(sound_on == 1) { @@ -442,7 +442,7 @@ void update_gbc_sound(u32 cpu_ticks) s32 volume_left, volume_right; u32 envelope_volume; s32 current_sample; - u32 sound_status = address16(io_registers, 0x84) & 0xFFF0; + u16 sound_status = read_ioreg(REG_SOUNDCNT_X) & 0xFFF0; s8 *sample_data; s8 *wave_bank; u8 *wave_ram = ((u8 *)io_registers) + 0x90; @@ -526,7 +526,7 @@ void update_gbc_sound(u32 cpu_ticks) } } - address16(io_registers, 0x84) = sound_status; + write_ioreg(REG_SOUNDCNT_X, sound_status); gbc_sound_last_cpu_ticks = cpu_ticks; gbc_sound_buffer_index = @@ -660,7 +660,7 @@ void render_audio(void) current_sample = 2047; if(current_sample < -2048) current_sample = -2048; - stream_base[i] = current_sample << 4; + stream_base[i] = current_sample * 16; source[i] = 0; } #ifdef __LIBRETRO__ @@ -31,22 +31,8 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline u32 enable_flags, u32 dispcnt, u32 bldcnt, const bitmap_layer_render_struct *layer_renderers); -#define no_op \ - -// This old version is not necessary if the palette is either being converted -// transparently or the ABGR 1555 format is being used natively. The direct -// version (without conversion) is much faster. - -#define tile_lookup_palette_full(palette, source) \ - current_pixel = palette[source]; \ - convert_palette(current_pixel) \ - -#define tile_lookup_palette(palette, source) \ - current_pixel = palette[source]; \ - - #define tile_expand_base_normal(index) \ - tile_lookup_palette(palette, current_pixel); \ + current_pixel = palette[current_pixel]; \ dest_ptr[index] = current_pixel \ #define tile_expand_transparent_normal(index) \ @@ -68,14 +54,14 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline #define color_combine_mask_a(layer) \ - ((io_registers[REG_BLDCNT] >> layer) & 0x01) \ + ((read_ioreg(REG_BLDCNT) >> layer) & 0x01) \ // For color blending operations, will create a mask that has in bit // 10 if the layer is target B, and bit 9 if the layer is target A. #define color_combine_mask(layer) \ (color_combine_mask_a(layer) | \ - ((io_registers[REG_BLDCNT] >> (layer + 7)) & 0x02)) << 9 \ + ((read_ioreg(REG_BLDCNT) >> (layer + 7)) & 0x02)) << 9 \ // For alpha blending renderers, draw the palette index (9bpp) and // layer bits rather than the raw RGB. For the base this should write to @@ -183,7 +169,7 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline // Get the current tile from the map in 8bpp mode #define get_tile_8bpp() \ - current_tile = *map_ptr; \ + current_tile = eswap16(*map_ptr); \ tile_ptr = tile_base + ((current_tile & 0x3FF) * 64) \ @@ -243,16 +229,16 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline #define partial_tile_right_noflip_8bpp(combine_op, alpha_op) \ if(partial_tile_offset >= 4) \ { \ - current_pixels = *((u32 *)(tile_ptr + 4)) >> \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) >> \ ((partial_tile_offset - 4) * 8); \ partial_tile_8bpp(combine_op, alpha_op); \ } \ else \ { \ partial_tile_run -= 4; \ - current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 8); \ + current_pixels = eswap32(*((u32 *)tile_ptr)) >> (partial_tile_offset * 8);\ partial_tile_8bpp(combine_op, alpha_op); \ - current_pixels = *((u32 *)(tile_ptr + 4)); \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \ advance_dest_ptr_##combine_op(4); \ } \ @@ -264,19 +250,19 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline #define partial_tile_mid_noflip_8bpp(combine_op, alpha_op) \ if(partial_tile_offset >= 4) \ { \ - current_pixels = *((u32 *)(tile_ptr + 4)) >> \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) >> \ ((partial_tile_offset - 4) * 8); \ } \ else \ { \ - current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 8); \ + current_pixels = eswap32(*((u32 *)tile_ptr)) >> (partial_tile_offset * 8);\ if((partial_tile_offset + partial_tile_run) > 4) \ { \ u32 old_run = partial_tile_run; \ partial_tile_run = 4 - partial_tile_offset; \ partial_tile_8bpp(combine_op, alpha_op); \ partial_tile_run = old_run - partial_tile_run; \ - current_pixels = *((u32 *)(tile_ptr + 4)); \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ } \ } \ partial_tile_8bpp(combine_op, alpha_op); \ @@ -288,23 +274,23 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline #define partial_tile_left_noflip_8bpp(combine_op, alpha_op) \ if(partial_tile_run >= 4) \ { \ - current_pixels = *((u32 *)tile_ptr); \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \ advance_dest_ptr_##combine_op(4); \ tile_ptr += 4; \ partial_tile_run -= 4; \ } \ \ - current_pixels = *((u32 *)(tile_ptr)); \ + current_pixels = eswap32(*((u32 *)(tile_ptr))); \ partial_tile_8bpp(combine_op, alpha_op) \ // Draws a non-clipped (complete) 8bpp tile. #define tile_noflip_8bpp(combine_op, alpha_op) \ - current_pixels = *((u32 *)tile_ptr); \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \ - current_pixels = *((u32 *)(tile_ptr + 4)); \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ tile_8bpp_draw_four_##combine_op(4, alpha_op, noflip) \ @@ -321,26 +307,28 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline #define partial_tile_right_flip_8bpp(combine_op, alpha_op) \ if(partial_tile_offset >= 4) \ { \ - current_pixels = *((u32 *)tile_ptr) << ((partial_tile_offset - 4) * 8); \ + current_pixels = eswap32(*((u32 *)tile_ptr)) << \ + ((partial_tile_offset - 4) * 8); \ partial_tile_flip_8bpp(combine_op, alpha_op); \ } \ else \ { \ partial_tile_run -= 4; \ - current_pixels = *((u32 *)(tile_ptr + 4)) << \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) << \ ((partial_tile_offset - 4) * 8); \ partial_tile_flip_8bpp(combine_op, alpha_op); \ - current_pixels = *((u32 *)tile_ptr); \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \ advance_dest_ptr_##combine_op(4); \ } \ #define partial_tile_mid_flip_8bpp(combine_op, alpha_op) \ if(partial_tile_offset >= 4) \ - current_pixels = *((u32 *)tile_ptr) << ((partial_tile_offset - 4) * 8); \ + current_pixels = eswap32(*((u32 *)tile_ptr)) << \ + ((partial_tile_offset - 4) * 8); \ else \ { \ - current_pixels = *((u32 *)(tile_ptr + 4)) << \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) << \ ((partial_tile_offset - 4) * 8); \ \ if((partial_tile_offset + partial_tile_run) > 4) \ @@ -349,7 +337,7 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline partial_tile_run = 4 - partial_tile_offset; \ partial_tile_flip_8bpp(combine_op, alpha_op); \ partial_tile_run = old_run - partial_tile_run; \ - current_pixels = *((u32 *)(tile_ptr)); \ + current_pixels = eswap32(*((u32 *)(tile_ptr))); \ } \ } \ partial_tile_flip_8bpp(combine_op, alpha_op); \ @@ -357,20 +345,20 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline #define partial_tile_left_flip_8bpp(combine_op, alpha_op) \ if(partial_tile_run >= 4) \ { \ - current_pixels = *((u32 *)(tile_ptr + 4)); \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \ advance_dest_ptr_##combine_op(4); \ tile_ptr -= 4; \ partial_tile_run -= 4; \ } \ \ - current_pixels = *((u32 *)(tile_ptr + 4)); \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ partial_tile_flip_8bpp(combine_op, alpha_op) \ #define tile_flip_8bpp(combine_op, alpha_op) \ - current_pixels = *((u32 *)(tile_ptr + 4)); \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \ - current_pixels = *((u32 *)tile_ptr); \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ tile_8bpp_draw_four_##combine_op(4, alpha_op, flip) \ @@ -536,7 +524,7 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline // the pixel block. #define get_tile_4bpp() \ - current_tile = *map_ptr; \ + current_tile = eswap16(*map_ptr); \ current_palette = (current_tile >> 12) << 4; \ tile_ptr = tile_base + ((current_tile & 0x3FF) * 32); \ @@ -557,7 +545,7 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline // how many to draw. #define partial_tile_right_noflip_4bpp(combine_op, alpha_op) \ - current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 4); \ + current_pixels = eswap32(*((u32 *)tile_ptr)) >> (partial_tile_offset * 4); \ partial_tile_4bpp(combine_op, alpha_op) \ @@ -571,13 +559,13 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline // partial_tile_offset is how many to draw. #define partial_tile_left_noflip_4bpp(combine_op, alpha_op) \ - current_pixels = *((u32 *)tile_ptr); \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ partial_tile_4bpp(combine_op, alpha_op) \ // Draws a complete 4bpp tile row (not clipped) #define tile_noflip_4bpp(combine_op, alpha_op) \ - current_pixels = *((u32 *)tile_ptr); \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ tile_4bpp_draw_eight_##combine_op(alpha_op, noflip) \ @@ -592,18 +580,18 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline } \ #define partial_tile_right_flip_4bpp(combine_op, alpha_op) \ - current_pixels = *((u32 *)tile_ptr) << (partial_tile_offset * 4); \ + current_pixels = eswap32(*((u32 *)tile_ptr)) << (partial_tile_offset * 4); \ partial_tile_flip_4bpp(combine_op, alpha_op) \ #define partial_tile_mid_flip_4bpp(combine_op, alpha_op) \ partial_tile_right_flip_4bpp(combine_op, alpha_op) \ #define partial_tile_left_flip_4bpp(combine_op, alpha_op) \ - current_pixels = *((u32 *)tile_ptr); \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ partial_tile_flip_4bpp(combine_op, alpha_op) \ #define tile_flip_4bpp(combine_op, alpha_op) \ - current_pixels = *((u32 *)tile_ptr); \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ tile_4bpp_draw_eight_##combine_op(alpha_op, flip) \ @@ -868,13 +856,13 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void *scanline) { render_scanline_extra_variables_base_normal(text); - u32 bg_control = io_registers[REG_BG0CNT + layer]; + u32 bg_control = read_ioreg(REG_BG0CNT + layer); u32 map_size = (bg_control >> 14) & 0x03; u32 map_width = map_widths[map_size]; u32 horizontal_offset = - (io_registers[REG_BG0HOFS + (layer * 2)] + start) % 512; - u32 vertical_offset = (io_registers[REG_VCOUNT] + - io_registers[REG_BG0VOFS + (layer * 2)]) % 512; + (read_ioreg(REG_BG0HOFS + (layer * 2)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_VCOUNT) + + read_ioreg(REG_BG0VOFS + (layer * 2))) % 512; u32 current_pixel; u32 current_pixels; u32 partial_tile_run = 0; @@ -1055,13 +1043,13 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 end, void *scanline) { render_scanline_extra_variables_transparent_normal(text); - u32 bg_control = io_registers[REG_BG0CNT + layer]; + u32 bg_control = read_ioreg(REG_BG0CNT + layer); u32 map_size = (bg_control >> 14) & 0x03; u32 map_width = map_widths[map_size]; u32 horizontal_offset = - (io_registers[REG_BG0HOFS + (layer * 2)] + start) % 512; - u32 vertical_offset = (io_registers[REG_VCOUNT] + - io_registers[REG_BG0VOFS + (layer * 2)]) % 512; + (read_ioreg(REG_BG0HOFS + (layer * 2)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_VCOUNT) + + read_ioreg(REG_BG0VOFS + (layer * 2))) % 512; u32 current_pixel; u32 current_pixels; u32 partial_tile_run = 0; @@ -1241,13 +1229,13 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, void *scanline) { render_scanline_extra_variables_base_color16(text); - u32 bg_control = io_registers[REG_BG0CNT + layer]; + u32 bg_control = read_ioreg(REG_BG0CNT + layer); u32 map_size = (bg_control >> 14) & 0x03; u32 map_width = map_widths[map_size]; u32 horizontal_offset = - (io_registers[REG_BG0HOFS + (layer * 2)] + start) % 512; - u32 vertical_offset = (io_registers[REG_VCOUNT] + - io_registers[REG_BG0VOFS + (layer * 2)]) % 512; + (read_ioreg(REG_BG0HOFS + (layer * 2)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_VCOUNT) + + read_ioreg(REG_BG0VOFS + (layer * 2))) % 512; u32 current_pixel; u32 current_pixels; u32 partial_tile_run = 0; @@ -1426,13 +1414,13 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 end, void *scanline) { render_scanline_extra_variables_transparent_color16(text); - u32 bg_control = io_registers[REG_BG0CNT + layer]; + u32 bg_control = read_ioreg(REG_BG0CNT + layer); u32 map_size = (bg_control >> 14) & 0x03; u32 map_width = map_widths[map_size]; u32 horizontal_offset = - (io_registers[REG_BG0HOFS + (layer * 2)] + start) % 512; - u32 vertical_offset = (io_registers[REG_VCOUNT] + - io_registers[REG_BG0VOFS + (layer * 2)]) % 512; + (read_ioreg(REG_BG0HOFS + (layer * 2)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_VCOUNT) + + read_ioreg(REG_BG0VOFS + (layer * 2))) % 512; u32 current_pixel; u32 current_pixels; u32 partial_tile_run = 0; @@ -1611,13 +1599,13 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, void *scanline) { render_scanline_extra_variables_base_color32(text); - u32 bg_control = io_registers[REG_BG0CNT + layer]; + u32 bg_control = read_ioreg(REG_BG0CNT + layer); u32 map_size = (bg_control >> 14) & 0x03; u32 map_width = map_widths[map_size]; u32 horizontal_offset = - (io_registers[REG_BG0HOFS + (layer * 2)] + start) % 512; - u32 vertical_offset = (io_registers[REG_VCOUNT] + - io_registers[REG_BG0VOFS + (layer * 2)]) % 512; + (read_ioreg(REG_BG0HOFS + (layer * 2)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_VCOUNT) + + read_ioreg(REG_BG0VOFS + (layer * 2))) % 512; u32 current_pixel; u32 current_pixels; u32 partial_tile_run = 0; @@ -1796,13 +1784,13 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 end, void *scanline) { render_scanline_extra_variables_transparent_color32(text); - u32 bg_control = io_registers[REG_BG0CNT + layer]; + u32 bg_control = read_ioreg(REG_BG0CNT + layer); u32 map_size = (bg_control >> 14) & 0x03; u32 map_width = map_widths[map_size]; u32 horizontal_offset = - (io_registers[REG_BG0HOFS + (layer * 2)] + start) % 512; - u32 vertical_offset = (io_registers[REG_VCOUNT] + - io_registers[REG_BG0VOFS + (layer * 2)]) % 512; + (read_ioreg(REG_BG0HOFS + (layer * 2)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_VCOUNT) + + read_ioreg(REG_BG0VOFS + (layer * 2))) % 512; u32 current_pixel; u32 current_pixels; u32 partial_tile_run = 0; @@ -1983,13 +1971,13 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void *scanline) { render_scanline_extra_variables_base_alpha(text); - u32 bg_control = io_registers[REG_BG0CNT + layer]; + u32 bg_control = read_ioreg(REG_BG0CNT + layer); u32 map_size = (bg_control >> 14) & 0x03; u32 map_width = map_widths[map_size]; u32 horizontal_offset = - (io_registers[REG_BG0HOFS + (layer * 2)] + start) % 512; - u32 vertical_offset = (io_registers[REG_VCOUNT] + - io_registers[REG_BG0VOFS + (layer * 2)]) % 512; + (read_ioreg(REG_BG0HOFS + (layer * 2)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_VCOUNT) + + read_ioreg(REG_BG0VOFS + (layer * 2))) % 512; u32 current_pixel; u32 current_pixels; u32 partial_tile_run = 0; @@ -2166,13 +2154,13 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end, void *scanline) { render_scanline_extra_variables_transparent_alpha(text); - u32 bg_control = io_registers[REG_BG0CNT + layer]; + u32 bg_control = read_ioreg(REG_BG0CNT + layer); u32 map_size = (bg_control >> 14) & 0x03; u32 map_width = map_widths[map_size]; u32 horizontal_offset = - (io_registers[REG_BG0HOFS + (layer * 2)] + start) % 512; - u32 vertical_offset = (io_registers[REG_VCOUNT] + - io_registers[REG_BG0VOFS + (layer * 2)]) % 512; + (read_ioreg(REG_BG0HOFS + (layer * 2)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_VCOUNT) + + read_ioreg(REG_BG0VOFS + (layer * 2))) % 512; u32 current_pixel; u32 current_pixels; u32 partial_tile_run = 0; @@ -2522,7 +2510,7 @@ void render_scanline_affine_##combine_op##_##alpha_op(u32 layer, \ u32 start, u32 end, void *scanline) \ { \ render_scanline_extra_variables_##combine_op##_##alpha_op(affine); \ - u32 bg_control = io_registers[REG_BG0CNT + layer]; \ + u32 bg_control = read_ioreg(REG_BG0CNT + layer); \ u32 current_pixel; \ s32 source_x, source_y; \ u32 pixel_x, pixel_y; \ @@ -2539,8 +2527,8 @@ void render_scanline_affine_##combine_op##_##alpha_op(u32 layer, \ render_scanline_dest_##alpha_op *dest_ptr = \ ((render_scanline_dest_##alpha_op *)scanline) + start; \ \ - dx = (s16)io_registers[REG_BG2PA + layer_offset]; \ - dy = (s16)io_registers[REG_BG2PC + layer_offset]; \ + dx = (s16)read_ioreg(REG_BG2PA + layer_offset); \ + dy = (s16)read_ioreg(REG_BG2PC + layer_offset); \ source_x = affine_reference_x[layer - 2] + (start * dx); \ source_y = affine_reference_y[layer - 2] + (start * dy); \ \ @@ -2609,7 +2597,7 @@ render_scanline_affine_builder(transparent, alpha); \ for(i = 0; (s32)i < (s32)end; i++) \ { \ - current_pixel = *src_ptr; \ + current_pixel = srcread_##type(*src_ptr); \ bitmap_render_pixel_##type(alpha_op); \ src_ptr++; \ dest_ptr++; \ @@ -2637,7 +2625,7 @@ render_scanline_affine_builder(transparent, alpha); if((u32)pixel_x >= (u32)width) \ break; \ \ - current_pixel = src_ptr[pixel_x]; \ + current_pixel = srcread_##type(src_ptr[pixel_x]); \ bitmap_render_pixel_##type(alpha_op); \ \ source_x += dx; \ @@ -2669,7 +2657,7 @@ render_scanline_affine_builder(transparent, alpha); if(((u32)pixel_x >= (u32)width) || ((u32)pixel_y >= (u32)height)) \ break; \ \ - current_pixel = src_ptr[pixel_x + (pixel_y * width)]; \ + current_pixel = srcread_##type(src_ptr[pixel_x + (pixel_y * width)]); \ bitmap_render_pixel_##type(alpha_op); \ \ source_x += dx; \ @@ -2683,16 +2671,19 @@ render_scanline_affine_builder(transparent, alpha); #define render_scanline_vram_setup_mode5() \ u16 *src_ptr = (u16 *)vram; \ - if(io_registers[REG_DISPCNT] & 0x10) \ + if(read_ioreg(REG_DISPCNT) & 0x10) \ src_ptr = (u16 *)(vram + 0xA000); \ #define render_scanline_vram_setup_mode4() \ u16 *palette = palette_ram_converted; \ u8 *src_ptr = vram; \ - if(io_registers[REG_DISPCNT] & 0x10) \ + if(read_ioreg(REG_DISPCNT) & 0x10) \ src_ptr = vram + 0xA000; \ +#define srcread_mode3(v) eswap16(v) +#define srcread_mode5(v) eswap16(v) +#define srcread_mode4(v) (v) // Build bitmap scanline rendering functions. @@ -2705,8 +2696,8 @@ static void render_scanline_bitmap_##type##_##alpha_op(u32 start, u32 end, \ s32 source_x, source_y; \ s32 pixel_x, pixel_y; \ \ - s32 dx = (s16)io_registers[REG_BG2PA]; \ - s32 dy = (s16)io_registers[REG_BG2PC]; \ + s32 dx = (s16)read_ioreg(REG_BG2PA); \ + s32 dy = (s16)read_ioreg(REG_BG2PC); \ \ u32 i; \ \ @@ -3058,11 +3049,11 @@ static const bitmap_layer_render_struct bitmap_mode_renderers[3] = #define obj_render_affine(combine_op, color_depth, alpha_op, map_space) \ { \ - s16 *params = (s16 *)oam_ram + (((obj_attribute_1 >> 9) & 0x1F) * 16); \ - s32 dx = params[3]; \ - s32 dmx = params[7]; \ - s32 dy = params[11]; \ - s32 dmy = params[15]; \ + u16 *params = (u16 *)oam_ram + (((obj_attribute_1 >> 9) & 0x1F) * 16); \ + s32 dx = (s16)eswap16(params[3]); \ + s32 dmx = (s16)eswap16(params[7]); \ + s32 dy = (s16)eswap16(params[11]); \ + s32 dmy = (s16)eswap16(params[15]); \ s32 source_x, source_y; \ s32 tile_x, tile_y; \ u32 tile_map_offset; \ @@ -3163,9 +3154,9 @@ static u32 obj_alpha_count[160]; u32 dest \ #define render_scanline_obj_extra_variables_copy(type) \ - u32 bldcnt = io_registers[REG_BLDCNT]; \ - u32 dispcnt = io_registers[REG_DISPCNT]; \ - u32 obj_enable = io_registers[REG_WINOUT] >> 8; \ + u32 bldcnt = read_ioreg(REG_BLDCNT); \ + u32 dispcnt = read_ioreg(REG_DISPCNT); \ + u32 obj_enable = read_ioreg(REG_WINOUT) >> 8; \ render_scanline_layer_functions_##type(); \ u32 copy_start, copy_end; \ u16 copy_buffer[240]; \ @@ -3278,7 +3269,7 @@ static void render_scanline_obj_##alpha_op##_##map_space(u32 priority, \ s32 obj_size; \ s32 obj_width, obj_height; \ u32 obj_attribute_0, obj_attribute_1, obj_attribute_2; \ - s32 vcount = io_registers[REG_VCOUNT]; \ + s32 vcount = read_ioreg(REG_VCOUNT); \ u32 tile_run; \ u32 current_pixels; \ u32 current_pixel; \ @@ -3296,9 +3287,9 @@ static void render_scanline_obj_##alpha_op##_##map_space(u32 priority, \ for(obj_num = 0; obj_num < obj_count; obj_num++) \ { \ oam_ptr = oam_ram + (obj_list[obj_num] * 4); \ - obj_attribute_0 = oam_ptr[0]; \ - obj_attribute_1 = oam_ptr[1]; \ - obj_attribute_2 = oam_ptr[2]; \ + obj_attribute_0 = eswap16(oam_ptr[0]); \ + obj_attribute_1 = eswap16(oam_ptr[1]); \ + obj_attribute_2 = eswap16(oam_ptr[2]); \ obj_size = ((obj_attribute_0 >> 12) & 0x0C) | (obj_attribute_1 >> 14); \ \ obj_x = (s32)(obj_attribute_1 << 23) >> 23; \ @@ -3355,8 +3346,8 @@ static void order_obj(u32 video_mode) for(obj_num = 127; obj_num >= 0; obj_num--, oam_ptr -= 4) { - obj_attribute_0 = oam_ptr[0]; - obj_attribute_2 = oam_ptr[2]; + obj_attribute_0 = eswap16(oam_ptr[0]); + obj_attribute_2 = eswap16(oam_ptr[2]); obj_size = obj_attribute_0 & 0xC000; obj_priority = (obj_attribute_2 >> 10) & 0x03; obj_mode = (obj_attribute_0 >> 10) & 0x03; @@ -3369,7 +3360,7 @@ static void order_obj(u32 video_mode) if(obj_y > 160) obj_y -= 256; - obj_attribute_1 = oam_ptr[1]; + obj_attribute_1 = eswap16(oam_ptr[1]); obj_size = ((obj_size >> 12) & 0x0C) | (obj_attribute_1 >> 14); obj_height = obj_height_table[obj_size]; obj_width = obj_width_table[obj_size]; @@ -3436,14 +3427,14 @@ static void order_layers(u32 layer_flags) for(layer_number = 3; layer_number >= 0; layer_number--) { if(((layer_flags >> layer_number) & 1) && - ((io_registers[REG_BG0CNT + layer_number] & 0x03) == priority)) + ((read_ioreg(REG_BG0CNT + layer_number) & 0x03) == priority)) { layer_order[layer_count] = layer_number; layer_count++; } } - if((obj_priority_count[priority][io_registers[REG_VCOUNT]] > 0) + if((obj_priority_count[priority][read_ioreg(REG_VCOUNT)] > 0) && (layer_flags & 0x10)) { layer_order[layer_count] = priority | 0x04; @@ -3614,7 +3605,7 @@ void expand_blend(u32 *screen_src_ptr, u16 *screen_dest_ptr, { u32 pixel_pair; u32 pixel_top, pixel_bottom; - u32 bldalpha = io_registers[REG_BLDALPHA]; + u32 bldalpha = read_ioreg(REG_BLDALPHA); u32 blend_a = bldalpha & 0x1F; u32 blend_b = (bldalpha >> 8) & 0x1F; u32 i; @@ -3645,7 +3636,7 @@ static void expand_darken(u16 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) { u32 pixel_top; - s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F); + s32 blend = 16 - (read_ioreg(REG_BLDY) & 0x1F); u32 i; if(blend < 0) @@ -3661,7 +3652,7 @@ static void expand_brighten(u16 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) { u32 pixel_top; - u32 blend = io_registers[REG_BLDY] & 0x1F; + u32 blend = read_ioreg(REG_BLDY) & 0x1F; u32 upper; u32 i; @@ -3682,10 +3673,10 @@ static void expand_brighten(u16 *screen_src_ptr, u16 *screen_dest_ptr, static void expand_darken_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) { - s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F); + s32 blend = 16 - (read_ioreg(REG_BLDY) & 0x1F); u32 pixel_pair; u32 pixel_top, pixel_bottom; - u32 bldalpha = io_registers[REG_BLDALPHA]; + u32 bldalpha = read_ioreg(REG_BLDALPHA); u32 blend_a = bldalpha & 0x1F; u32 blend_b = (bldalpha >> 8) & 0x1F; u32 i; @@ -3706,10 +3697,10 @@ static void expand_darken_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_pt static void expand_brighten_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) { - s32 blend = io_registers[REG_BLDY] & 0x1F; + s32 blend = read_ioreg(REG_BLDY) & 0x1F; u32 pixel_pair; u32 pixel_top, pixel_bottom; - u32 bldalpha = io_registers[REG_BLDALPHA]; + u32 bldalpha = read_ioreg(REG_BLDALPHA); u32 blend_a = bldalpha & 0x1F; u32 blend_b = (bldalpha >> 8) & 0x1F; u32 upper; @@ -3784,20 +3775,20 @@ static void expand_brighten_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ } \ #define render_condition_alpha \ - (((io_registers[REG_BLDALPHA] & 0x1F1F) != 0x001F) && \ - ((io_registers[REG_BLDCNT] & 0x3F) != 0) && \ - ((io_registers[REG_BLDCNT] & 0x3F00) != 0)) \ + (((read_ioreg(REG_BLDALPHA) & 0x1F1F) != 0x001F) && \ + ((read_ioreg(REG_BLDCNT) & 0x3F) != 0) && \ + ((read_ioreg(REG_BLDCNT) & 0x3F00) != 0)) \ #define render_condition_fade \ - (((io_registers[REG_BLDY] & 0x1F) != 0) && \ - ((io_registers[REG_BLDCNT] & 0x3F) != 0)) \ + (((read_ioreg(REG_BLDY) & 0x1F) != 0) && \ + ((read_ioreg(REG_BLDCNT) & 0x3F) != 0)) \ #define render_layers_color_effect(renderer, layer_condition, \ alpha_condition, fade_condition, _start, _end) \ { \ if(layer_condition) \ { \ - if(obj_alpha_count[io_registers[REG_VCOUNT]] > 0) \ + if(obj_alpha_count[read_ioreg(REG_VCOUNT)] > 0) \ { \ /* Render based on special effects mode. */ \ u32 screen_buffer[240]; \ @@ -3902,7 +3893,7 @@ static void expand_brighten_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ { \ if(color_combine_mask_a(5)) \ { \ - u32 blend = io_registers[REG_BLDY] & 0x1F; \ + u32 blend = read_ioreg(REG_BLDY) & 0x1F; \ u32 upper; \ \ if(blend > 16) \ @@ -3921,7 +3912,7 @@ static void expand_brighten_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ { \ if(color_combine_mask_a(5)) \ { \ - s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F); \ + s32 blend = 16 - (read_ioreg(REG_BLDY) & 0x1F); \ \ if(blend < 0) \ blend = 0; \ @@ -3942,7 +3933,7 @@ static void render_scanline_tile(u16 *scanline, u32 dispcnt) { u32 current_layer; u32 layer_order_pos; - u32 bldcnt = io_registers[REG_BLDCNT]; + u32 bldcnt = read_ioreg(REG_BLDCNT); render_scanline_layer_functions_tile(); render_layers_color_effect(render_layers, layer_count, @@ -4116,9 +4107,9 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline #define window_x_coords(window_number) \ window_##window_number##_x1 = \ - io_registers[REG_WIN##window_number##H] >> 8; \ + read_ioreg(REG_WIN##window_number##H) >> 8; \ window_##window_number##_x2 = \ - io_registers[REG_WIN##window_number##H] & 0xFF; \ + read_ioreg(REG_WIN##window_number##H) & 0xFF; \ window_##window_number##_enable = \ (winin >> (window_number * 8)) & 0x3F; \ \ @@ -4133,9 +4124,9 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline u32 window_##window_number##_y1, window_##window_number##_y2; \ u32 window_##window_number##_enable = 0; \ window_##window_number##_y1 = \ - io_registers[REG_WIN##window_number##V] >> 8; \ + read_ioreg(REG_WIN##window_number##V) >> 8; \ window_##window_number##_y2 = \ - io_registers[REG_WIN##window_number##V] & 0xFF; \ + read_ioreg(REG_WIN##window_number##V) & 0xFF; \ \ if(window_##window_number##_y1 > window_##window_number##_y2) \ { \ @@ -4306,7 +4297,7 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline #define render_window_single(type, window_number) \ - u32 winin = io_registers[REG_WININ]; \ + u32 winin = read_ioreg(REG_WININ); \ window_coords(window_number); \ if(window_##window_number##_x1 > window_##window_number##_x2) \ { \ @@ -4344,9 +4335,9 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline #define render_scanline_window_builder(type) \ static void render_scanline_window_##type(u16 *scanline, u32 dispcnt) \ { \ - u32 vcount = io_registers[REG_VCOUNT]; \ - u32 winout = io_registers[REG_WINOUT]; \ - u32 bldcnt = io_registers[REG_BLDCNT]; \ + u32 vcount = read_ioreg(REG_VCOUNT); \ + u32 winout = read_ioreg(REG_WINOUT); \ + u32 bldcnt = read_ioreg(REG_BLDCNT); \ u32 window_out_enable = winout & 0x3F; \ \ render_scanline_layer_functions_##type(); \ @@ -4370,7 +4361,7 @@ static void render_scanline_window_##type(u16 *scanline, u32 dispcnt) \ /* Windows 1 and 2 */ \ case 0x03: \ { \ - u32 winin = io_registers[REG_WININ]; \ + u32 winin = read_ioreg(REG_WININ); \ window_coords(0); \ window_coords(1); \ render_window_multi(type, 0, 1); \ @@ -4387,7 +4378,7 @@ static void render_scanline_window_##type(u16 *scanline, u32 dispcnt) \ /* Window 0 and OBJ window */ \ case 0x05: \ { \ - u32 winin = io_registers[REG_WININ]; \ + u32 winin = read_ioreg(REG_WININ); \ window_coords(0); \ render_window_multi(type, 0, obj); \ break; \ @@ -4396,7 +4387,7 @@ static void render_scanline_window_##type(u16 *scanline, u32 dispcnt) \ /* Window 1 and OBJ window */ \ case 0x06: \ { \ - u32 winin = io_registers[REG_WININ]; \ + u32 winin = read_ioreg(REG_WININ); \ window_coords(1); \ render_window_multi(type, 1, obj); \ break; \ @@ -4405,7 +4396,7 @@ static void render_scanline_window_##type(u16 *scanline, u32 dispcnt) \ /* Window 0, 1, and OBJ window */ \ case 0x07: \ { \ - u32 winin = io_registers[REG_WININ]; \ + u32 winin = read_ioreg(REG_WININ); \ window_coords(0); \ window_coords(1); \ render_window_multi(type, 0, 1_obj); \ @@ -4422,8 +4413,8 @@ static const u32 active_layers[6] = { 0x1F, 0x17, 0x1C, 0x14, 0x14, 0x14 }; void update_scanline(void) { u32 pitch = get_screen_pitch(); - u32 dispcnt = io_registers[REG_DISPCNT]; - u32 vcount = io_registers[REG_VCOUNT]; + u32 dispcnt = read_ioreg(REG_DISPCNT); + u32 vcount = read_ioreg(REG_VCOUNT); u16 *screen_offset = get_screen_pixels() + (vcount * pitch); u32 video_mode = dispcnt & 0x07; @@ -4467,10 +4458,10 @@ void update_scanline(void) } } - affine_reference_x[0] += (s16)io_registers[REG_BG2PB]; - affine_reference_y[0] += (s16)io_registers[REG_BG2PD]; - affine_reference_x[1] += (s16)io_registers[REG_BG3PB]; - affine_reference_y[1] += (s16)io_registers[REG_BG3PD]; + affine_reference_x[0] += (s16)read_ioreg(REG_BG2PB); + affine_reference_y[0] += (s16)read_ioreg(REG_BG2PD); + affine_reference_x[1] += (s16)read_ioreg(REG_BG3PB); + affine_reference_y[1] += (s16)read_ioreg(REG_BG3PD); } #define video_savestate_builder(type) \ diff --git a/x86/x86_emit.h b/x86/x86_emit.h index ef79110..69c1f8e 100644 --- a/x86/x86_emit.h +++ b/x86/x86_emit.h @@ -325,7 +325,7 @@ typedef enum x86_emit_mov_reg_mem(reg_##ireg, reg_base, reg_index * 4); \ #define generate_load_pc(ireg, new_pc) \ - x86_emit_mov_reg_imm(reg_##ireg, new_pc) \ + x86_emit_mov_reg_imm(reg_##ireg, (new_pc)) \ #define generate_load_imm(ireg, imm) \ x86_emit_mov_reg_imm(reg_##ireg, imm) \ @@ -1894,6 +1894,10 @@ u32 function_cc execute_ror_imm_op(u32 value, u32 shift) // Operation types: imm, mem_reg, mem_imm +#define thumb_load_pc_pool_const(reg_rd, value) \ + generate_load_pc(a0, (value)); \ + generate_store_reg(a0, reg_rd) + #define thumb_access_memory_load(mem_type, reg_rd) \ cycle_count += 2; \ generate_function_call(execute_load_##mem_type); \ @@ -2236,6 +2240,12 @@ static void function_cc execute_swi(u32 pc) generate_indirect_branch_cycle_update(dual); \ } \ +#define thumb_process_cheats() \ + generate_function_call(process_cheats); + +#define arm_process_cheats() \ + generate_function_call(process_cheats); + #define thumb_swi() \ generate_swi_hle_handler(opcode & 0xFF); \ generate_update_pc((pc + 2)); \ |