summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorneonloop2021-07-03 19:54:16 +0000
committerneonloop2021-07-03 19:54:16 +0000
commit2815c248d76932787fb58d5bbaa0f26be7bcb2be (patch)
treeeff2b1e2c458fcd0b5f96902382df944048d36b7
parent8dec6231614ba3f47d874d551ab83f4c5acb07cb (diff)
parent3d874ec5e3d5675ae9513264d857a3c6c9d2417c (diff)
downloadpicogpsp-2815c248d76932787fb58d5bbaa0f26be7bcb2be.tar.gz
picogpsp-2815c248d76932787fb58d5bbaa0f26be7bcb2be.tar.bz2
picogpsp-2815c248d76932787fb58d5bbaa0f26be7bcb2be.zip
Merge remote-tracking branch 'libretro/master' into pico-fe
-rw-r--r--.gitlab-ci.yml32
-rw-r--r--Makefile52
-rw-r--r--Makefile.common4
-rw-r--r--arm/arm_emit.h17
-rw-r--r--arm/arm_stub.S42
-rw-r--r--cheats.c544
-rw-r--r--cheats.h35
-rw-r--r--common.h16
-rw-r--r--cpu.c4368
-rw-r--r--cpu_threaded.c415
-rw-r--r--gba_memory.c465
-rw-r--r--gba_memory.h16
-rw-r--r--input.c76
-rw-r--r--input.h17
-rw-r--r--libretro.c142
-rw-r--r--libretro.h367
-rw-r--r--libretro_core_options.h126
-rw-r--r--main.c26
-rw-r--r--psp/mips_emit.h281
-rw-r--r--psp/mips_stub.S138
-rw-r--r--sound.c10
-rw-r--r--video.c267
-rw-r--r--x86/x86_emit.h12
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
diff --git a/Makefile b/Makefile
index 5d28045..5f7afff 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/cheats.c b/cheats.c
index f3e79e4..3594730 100644
--- a/cheats.c
+++ b/cheats.c
@@ -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;
- }
- }
- }
-}
diff --git a/cheats.h b/cheats.h
index e25ad73..b6e0a5d 100644
--- a/cheats.h
+++ b/cheats.h
@@ -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;
diff --git a/common.h b/common.h
index 9317849..714d607 100644
--- a/common.h
+++ b/common.h
@@ -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>
diff --git a/cpu.c b/cpu.c
index f56ab60..e334203 100644
--- a/cpu.c
+++ b/cpu.c
@@ -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];
diff --git a/input.c b/input.c
index c1763c8..76cd861 100644
--- a/input.c
+++ b/input.c
@@ -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;
}
diff --git a/input.h b/input.h
index bec7997..72c7e1e 100644
--- a/input.h
+++ b/input.h
@@ -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);
diff --git a/libretro.c b/libretro.c
index f74c0cd..a7d2765 100644
--- a/libretro.c
+++ b/libretro.c
@@ -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 */
diff --git a/libretro.h b/libretro.h
index d843114..32aa15f 100644
--- a/libretro.h
+++ b/libretro.h
@@ -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 },
};
diff --git a/main.c b/main.c
index 759aa94..461dbcf 100644
--- a/main.c
+++ b/main.c
@@ -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)
diff --git a/sound.c b/sound.c
index 70a04d5..a9d2140 100644
--- a/sound.c
+++ b/sound.c
@@ -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__
diff --git a/video.c b/video.c
index 4221f25..274b39c 100644
--- a/video.c
+++ b/video.c
@@ -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)); \