From 4fd456e1583a4c8686c8de87c2aeb1eb78125be1 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 5 May 2021 02:20:00 +0200 Subject: Adding Code Breaker cheat support This works on both interpreter and dynarec. Tested in MIPS, ARM and x86, still needs some more testing, some edge cases can be buggy. --- arm/arm_emit.h | 8 + arm/arm_stub.S | 16 ++ cheats.c | 531 +++++++++++++++++++++----------------------------------- cheats.h | 29 +--- cpu.c | 8 + cpu_threaded.c | 10 ++ gba_memory.c | 4 - libretro.c | 10 +- main.c | 4 +- psp/mips_emit.h | 7 + psp/mips_stub.S | 13 ++ x86/x86_emit.h | 6 + 12 files changed, 283 insertions(+), 363 deletions(-) diff --git a/arm/arm_emit.h b/arm/arm_emit.h index 1432617..4368a80 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 arm_cheat_hook(); u32 arm_update_gba_arm(u32 pc); u32 arm_update_gba_thumb(u32 pc); @@ -1876,6 +1878,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 944d36a..222bb21 100644 --- a/arm/arm_stub.S +++ b/arm/arm_stub.S @@ -288,6 +288,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. diff --git a/cheats.c b/cheats.c index f3e79e4..1a37081 100644 --- a/cheats.c +++ b/cheats.c @@ -19,373 +19,230 @@ #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 void update_hook_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 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 */ + } } - - *address_ptr = address; - *value_ptr = value; } -void add_cheats(char *cheats_filename) +static void process_cheat_codebreaker(cheat_type *cheat, u16 pad) { - 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; + unsigned j; + 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) + 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) { - *name_ptr = 0; - name_ptr++; + 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++) + { + write_memory16(address, value); + address += aincr; + value += vincr; + } } - - if(!strcasecmp(current_line, "gameshark_v1") || - !strcasecmp(current_line, "gameshark_v2") || - !strcasecmp(current_line, "PAR_v1") || - !strcasecmp(current_line, "PAR_v2")) + break; + case 5: /* Super code: copies bytes to a buffer addr */ + for (j = 0; j < value * 2 && i < cheat->cheat_count; j++) { - current_cheat_variant = CHEAT_TYPE_GAMESHARK_V1; + 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].address >> (40 - off*8); + break; + }; + write_memory8(address, bvalue); + address++; } - else - - if(!strcasecmp(current_line, "gameshark_v3") || - !strcasecmp(current_line, "PAR_v3")) + 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 1: + if ((pad & value) == value) + i++; + break; + case 2: + if ((pad & value) == 0) + i++; + break; + }; + break; + case 14: /* Increase 16/32 bit memory value */ + if (address & 1) { - current_cheat_variant = CHEAT_TYPE_GAMESHARK_V3; + u32 value32 = (u32)((s16)value); /* Sign extend to 32 bit */ + address &= ~1U; + write_memory32(address, read_memory32(address) + value32); } 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++; + write_memory16(address, read_memory16(address) + value); } + break; + case 15: /* Immediate and check and skip */ + if ((read_memory16(address) & value) == 0) + i++; + break; } - - fclose(cheats_file); } } -void process_cheat_gs1(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; + u32 i; - cheat_opcode = address >> 28; - address &= 0xFFFFFFF; - - switch(cheat_opcode) - { - case 0x0: - write_memory8(address, value); - break; + for(i = 0; i <= max_cheat; i++) + { + if(!cheats[i].cheat_active) + continue; - case 0x1: - write_memory16(address, value); - break; - - case 0x2: - write_memory32(address, value); - break; - - case 0x3: - { - u32 num_addresses = address & 0xFFFF; - u32 address1, address2; - u32 i2; - - for(i2 = 0; i2 < num_addresses; i2++) - { - address1 = code_ptr[0]; - address2 = code_ptr[1]; - code_ptr += 2; - i++; - - write_memory32(address1, value); - if(address2 != 0) - write_memory32(address2, value); - } - 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; - i++; - } - break; - - case 0xE: - if(read_memory16(value & 0xFFFFFFF) != (address & 0xFFFF)) - { - u32 skip = ((address >> 16) & 0x03); - code_ptr += skip * 2; - i += skip; - } - break; - - // Hook routine not supported yet (not important??) - case 0x0F: - break; - } - } + process_cheat_codebreaker(&cheats[i], 0x3ff ^ io_registers[REG_P1]); + } } -// These are especially incomplete. - -void process_cheat_gs3(cheat_type *cheat) +void cheat_clear() { - 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; - - case 0x2: - value = (value & 0xFFFF) + read_memory16(address); - write_memory16(address, value); - break; - - 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; - } - } + int i; + for (i = 0; i < MAX_CHEATS; i++) + { + cheats[i].cheat_count = 0; + cheats[i].cheat_active = false; + } + cheat_master_hook = 0xffffffff; } - -void process_cheats(void) +void cheat_parse(unsigned index, const char *code) { - u32 i; - - 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; + int pos = 0; + int codelen = strlen(code); + cheat_type *ch = &cheats[index]; + char buf[1024]; + + if (index >= MAX_CHEATS) + return; + if (codelen >= sizeof(buf)) + return; + + 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) + { + /* All codes were parsed! Process hook here */ + ch->cheat_active = true; + update_hook_codebreaker(ch); + return; + } + + /* TODO parse other types here */ +} - case CHEAT_TYPE_GAMESHARK_V3: - process_cheat_gs3(cheats + i); - break; - default: - break; - } - } - } -} diff --git a/cheats.h b/cheats.h index e25ad73..496df15 100644 --- a/cheats.h +++ b/cheats.h @@ -17,28 +17,17 @@ * 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; - -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; +#define MAX_CHEATS 20 +#define MAX_CHEAT_CODES 64 void process_cheats(void); -void add_cheats(char *cheats_filename); +void cheat_parse(unsigned index, const char *code); +void cheat_clear(); + +extern u32 cheat_master_hook; -#define MAX_CHEATS 16 +#endif -extern cheat_type cheats[MAX_CHEATS]; -extern u32 num_cheats; diff --git a/cpu.c b/cpu.c index badb9c2..5df8bb8 100644 --- a/cpu.c +++ b/cpu.c @@ -1679,6 +1679,10 @@ 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 */ @@ -3294,6 +3298,10 @@ 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 */ diff --git a/cpu_threaded.c b/cpu_threaded.c index a32b1b8..6874ae0 100644 --- a/cpu_threaded.c +++ b/cpu_threaded.c @@ -3303,6 +3303,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++; @@ -3502,6 +3507,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 8d3d39e..74d22c7 100644 --- a/gba_memory.c +++ b/gba_memory.c @@ -2380,7 +2380,6 @@ char gamepak_filename[512]; u32 load_gamepak(const struct retro_game_info* info, const char *name) { - char cheats_filename[256]; char *p; s32 file_size = load_gamepak_raw(name); @@ -2423,9 +2422,6 @@ u32 load_gamepak(const struct retro_game_info* info, 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; } diff --git a/libretro.c b/libretro.c index 21ca04f..40aec37 100644 --- a/libretro.c +++ b/libretro.c @@ -639,8 +639,16 @@ 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; + + cheat_parse(index, code); } -void retro_cheat_set(unsigned index, bool enabled, const char* code) {} static void extract_directory(char* buf, const char* path, size_t size) { diff --git a/main.c b/main.c index 759aa94..260edd5 100644 --- a/main.c +++ b/main.c @@ -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 diff --git a/psp/mips_emit.h b/psp/mips_emit.h index 12685e8..174fee5 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(); u32 execute_spsr_restore(u32 address); void execute_store_cpsr(u32 new_cpsr, u32 store_mask); @@ -2422,6 +2423,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) { diff --git a/psp/mips_stub.S b/psp/mips_stub.S index 08151db..786dc9e 100644 --- a/psp/mips_stub.S +++ b/psp/mips_stub.S @@ -44,6 +44,7 @@ .global init_emitter .global mips_lookup_pc .global smc_write +.global mips_cheat_hook .global write_io_epilogue .global memory_map_read @@ -256,6 +257,17 @@ 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: @@ -649,6 +661,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/x86/x86_emit.h b/x86/x86_emit.h index ef79110..45b663b 100644 --- a/x86/x86_emit.h +++ b/x86/x86_emit.h @@ -2236,6 +2236,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)); \ -- cgit v1.2.3 From 883f07f487ecd2e803cf2f924ab1e9a51e5f4fa9 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 5 May 2021 18:07:55 +0200 Subject: Fix small buf and add cheat error messages Some minor formating too --- arm/arm_emit.h | 4 ++-- cheats.c | 27 ++++++++++++++++++++++----- cheats.h | 12 ++++++++++-- libretro.c | 18 +++++++++++++++++- psp/mips_emit.h | 2 +- 5 files changed, 52 insertions(+), 11 deletions(-) diff --git a/arm/arm_emit.h b/arm/arm_emit.h index 4368a80..1b6b251 100644 --- a/arm/arm_emit.h +++ b/arm/arm_emit.h @@ -31,8 +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 arm_cheat_hook(); +void thumb_cheat_hook(void); +void arm_cheat_hook(void); u32 arm_update_gba_arm(u32 pc); u32 arm_update_gba_thumb(u32 pc); diff --git a/cheats.c b/cheats.c index 1a37081..17556ca 100644 --- a/cheats.c +++ b/cheats.c @@ -33,6 +33,19 @@ cheat_type cheats[MAX_CHEATS]; u32 max_cheat = 0; u32 cheat_master_hook = 0xffffffff; +static bool has_encrypted_codebreaker(cheat_type *cheat) +{ + int i; + for(i = 0; i < cheat->cheat_count; i++) + { + u32 code = cheat->codes[i].address; + u32 opcode = code >> 28; + if (opcode == 9) + return true; + } + return false; +} + static void update_hook_codebreaker(cheat_type *cheat) { int i; @@ -103,7 +116,7 @@ static void process_cheat_codebreaker(cheat_type *cheat, u16 pad) bvalue = cheat->codes[i].address >> (24 - off*8); break; case 4 ... 5: - bvalue = cheat->codes[i].address >> (40 - off*8); + bvalue = cheat->codes[i].value >> (40 - off*8); break; }; write_memory8(address, bvalue); @@ -192,7 +205,7 @@ void cheat_clear() cheat_master_hook = 0xffffffff; } -void cheat_parse(unsigned index, const char *code) +cheat_error cheat_parse(unsigned index, const char *code) { int pos = 0; int codelen = strlen(code); @@ -200,9 +213,9 @@ void cheat_parse(unsigned index, const char *code) char buf[1024]; if (index >= MAX_CHEATS) - return; + return CheatErrorTooMany; if (codelen >= sizeof(buf)) - return; + return CheatErrorTooBig; memcpy(buf, code, codelen+1); @@ -236,13 +249,17 @@ void cheat_parse(unsigned index, const char *code) 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; + return CheatNoError; } /* TODO parse other types here */ + return CheatErrorNotSupported; } diff --git a/cheats.h b/cheats.h index 496df15..b6e0a5d 100644 --- a/cheats.h +++ b/cheats.h @@ -23,9 +23,17 @@ #define MAX_CHEATS 20 #define MAX_CHEAT_CODES 64 +typedef enum { + CheatNoError = 0, + CheatErrorTooMany, + CheatErrorTooBig, + CheatErrorEncrypted, + CheatErrorNotSupported +} cheat_error; + void process_cheats(void); -void cheat_parse(unsigned index, const char *code); -void cheat_clear(); +cheat_error cheat_parse(unsigned index, const char *code); +void cheat_clear(void); extern u32 cheat_master_hook; diff --git a/libretro.c b/libretro.c index 40aec37..d8e9efc 100644 --- a/libretro.c +++ b/libretro.c @@ -647,7 +647,23 @@ void retro_cheat_set(unsigned index, bool enabled, const char* code) if (!enabled) return; - cheat_parse(index, code); + 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; + }; } static void extract_directory(char* buf, const char* path, size_t size) diff --git a/psp/mips_emit.h b/psp/mips_emit.h index 174fee5..aa00d86 100644 --- a/psp/mips_emit.h +++ b/psp/mips_emit.h @@ -44,7 +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 mips_cheat_hook(void); u32 execute_spsr_restore(u32 address); void execute_store_cpsr(u32 new_cpsr, u32 store_mask); -- cgit v1.2.3 From 7877a8888b4e607c3df77c5d5f47e2c880cb9a24 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 5 May 2021 21:31:24 +0200 Subject: Fix aligned32 reads in interpreter mode An address check was missing to read aligned 32 (stm/ldm) data from high mem areas (0xX0000000). This fixes SM4 EU that for some reason has some weird memory access (perhaps a bug?) --- cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu.c b/cpu.c index 5df8bb8..cd9bba6 100644 --- a/cpu.c +++ b/cpu.c @@ -1024,7 +1024,7 @@ 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); \ } \ -- cgit v1.2.3 From 37430f22c5234cb09f2325575806b830f947bf8a Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Fri, 7 May 2021 20:41:54 +0200 Subject: Small optimization (~2-4%) and whitespace cleanup! Cleans up a ton of whitespace in cpu.c (like 100KB!) and improves readability of some massive decode statements. Added an optimization for PC-relative loads (pool load) in ROM (since it's read only and cannot possibily change) that directly emits an immediate load. This is way faster, specially in MIPS/x86, ARM can be even faster if we rewrite the immediate load macros to also use a pool. --- Makefile | 1 + arm/arm_emit.h | 6 +- cpu.c | 4334 ++++++++++++++++++++++++------------------------------- cpu_threaded.c | 392 +---- libretro.c | 1 - psp/mips_emit.h | 7 +- x86/x86_emit.h | 6 +- 7 files changed, 2003 insertions(+), 2744 deletions(-) diff --git a/Makefile b/Makefile index 5d28045..f4c758f 100644 --- a/Makefile +++ b/Makefile @@ -376,6 +376,7 @@ 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 += -fno-caller-saves HAVE_DYNAREC := 1 CPU_ARCH := mips diff --git a/arm/arm_emit.h b/arm/arm_emit.h index 1b6b251..4516404 100644 --- a/arm/arm_emit.h +++ b/arm/arm_emit.h @@ -319,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) \ @@ -1658,6 +1658,10 @@ 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) \ + generate_load_pc(reg_a0, (value)); \ + generate_store_reg(reg_a0, reg_rd) + #define thumb_access_memory_load(mem_type, _rd) \ cycle_count += 2; \ generate_function_call(execute_load_##mem_type); \ diff --git a/cpu.c b/cpu.c index cd9bba6..d21eb66 100644 --- a/cpu.c +++ b/cpu.c @@ -1714,2546 +1714,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 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 0x4: + /* MI */ + if(!n_flag) + arm_next_instruction(); + break; -#ifdef HAVE_UNUSED - case 0xC0 ... 0xEF: - /* coprocessor instructions, reserved on GBA */ - break; -#endif + case 0x5: + /* PL */ + if(n_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 0x6: + /* VS */ + if(!v_flag) + arm_next_instruction(); + break; - /* End of Execute ARM instruction */ - cycles_remaining -= cycles_per_instruction; + case 0x7: + /* VC */ + if(v_flag) + arm_next_instruction(); + break; - if (pc == idle_loop_target_pc && cycles_remaining > 0) cycles_remaining = 0; - } while(cycles_remaining > 0); + case 0x8: + /* HI */ + if((c_flag == 0) | z_flag) + arm_next_instruction(); + break; - collapse_flags(); - cycles_remaining = update_gba(); - if (reg[COMPLETED_FRAME]) - return; - continue; + case 0x9: + /* LS */ + if(c_flag & (z_flag ^ 1)) + arm_next_instruction(); + break; - do - { -thumb_loop: + case 0xA: + /* GE */ + if(n_flag != v_flag) + arm_next_instruction(); + break; - collapse_flags(); + case 0xB: + /* LT */ + if(n_flag == v_flag) + arm_next_instruction(); + break; - /* Process cheats if we are about to execute the cheat hook */ - if (pc == cheat_master_hook) - process_cheats(); + 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: - case 0x6D: + /* 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 = address16(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 6874ae0..3cef5b1 100644 --- a/cpu_threaded.c +++ b/cpu_threaded.c @@ -1705,8 +1705,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 */ \ @@ -1743,165 +1744,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) \ @@ -2023,52 +1904,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: \ @@ -2143,165 +1993,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) \ diff --git a/libretro.c b/libretro.c index d8e9efc..4126eca 100644 --- a/libretro.c +++ b/libretro.c @@ -872,7 +872,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; diff --git a/psp/mips_emit.h b/psp/mips_emit.h index aa00d86..3f70f13 100644 --- a/psp/mips_emit.h +++ b/psp/mips_emit.h @@ -535,14 +535,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)); \ } \ } \ @@ -1697,6 +1697,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)); \ diff --git a/x86/x86_emit.h b/x86/x86_emit.h index 45b663b..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); \ -- cgit v1.2.3 From 134aba2b37ca7fec28b6fcd1cd6fca0dd1abc9ab Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Tue, 10 Nov 2020 12:03:10 +0000 Subject: Add dedicated RetroPad fast-forward button --- input.c | 34 ++++++++++++++++++++++++-- input.h | 5 ++++ libretro.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------- libretro.h | 55 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 13 deletions(-) diff --git a/input.c b/input.c index f4ab6e8..44455d2 100644 --- a/input.c +++ b/input.c @@ -19,11 +19,18 @@ #include "common.h" +bool libretro_supports_bitmasks = false; +bool libretro_supports_ff_override = false; +bool libretro_ff_enabled = false; +bool libretro_ff_enabled_prev = false; + 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]; @@ -53,8 +60,24 @@ u32 update_input(void) 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)); + } + 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); + } if ((new_key | old_key) != old_key) trigger_key(new_key); @@ -62,6 +85,13 @@ u32 update_input(void) old_key = new_key; io_registers[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..90fc930 100644 --- a/input.h +++ b/input.h @@ -56,6 +56,11 @@ 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; + void init_input(void); u32 update_input(void); void input_write_savestate(void); diff --git a/libretro.c b/libretro.c index 4126eca..28db9dd 100644 --- a/libretro.c +++ b/libretro.c @@ -339,6 +339,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; @@ -496,6 +521,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; @@ -813,20 +846,38 @@ static void check_variables(int started_from_load) 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_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 }, + }; + + 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_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 }, }; - environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, descriptors); + 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) @@ -921,6 +972,14 @@ 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; } unsigned retro_get_region(void) diff --git a/libretro.h b/libretro.h index d843114..bda0b77 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,16 @@ 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). + */ + /* VFS functionality */ /* File paths: @@ -2934,6 +2948,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 -- cgit v1.2.3 From 2877886ff1217d214dcb052457714ed05e00e02d Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Sat, 15 May 2021 21:43:10 +0200 Subject: Fix ARM dynarec unaligned 32 bit loads This might make a handful games slightly slower (but on the upper side they work now instead of crashing or restarting). Also while at it, fix some minor stuff in arm stubs for speed. --- arm/arm_stub.S | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/arm/arm_stub.S b/arm/arm_stub.S index 222bb21..d7203f8 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. @@ -777,12 +771,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 ;\ @@ -836,11 +828,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 -- cgit v1.2.3 From aafde6de7b2a28c1684c0e9fa62fee9a2a5398dd Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Mon, 17 May 2021 01:14:46 +0200 Subject: Add ROM mirroring and fix mult. cycle count This should correct some minor issues in some games. --- arm/arm_emit.h | 2 -- cpu_threaded.c | 13 +++++++++++++ gba_memory.c | 12 ++++++------ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/arm/arm_emit.h b/arm/arm_emit.h index 4516404..4198c7d 100644 --- a/arm/arm_emit.h +++ b/arm/arm_emit.h @@ -1239,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) diff --git a/cpu_threaded.c b/cpu_threaded.c index 3cef5b1..557b197 100644 --- a/cpu_threaded.c +++ b/cpu_threaded.c @@ -297,6 +297,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 \ @@ -314,6 +315,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: \ @@ -351,6 +353,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 \ @@ -368,6 +371,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: \ @@ -487,6 +491,7 @@ void translate_icache_sync() { { \ /* UMULL rd, rm, rs */ \ arm_multiply_long(u64, no, no); \ + cycle_count += 3; /* this is an aproximation :P */ \ } \ } \ else \ @@ -504,6 +509,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: \ @@ -541,6 +547,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 \ @@ -558,6 +565,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: \ @@ -595,6 +603,7 @@ void translate_icache_sync() { { \ /* SMULL rd, rm, rs */ \ arm_multiply_long(s64, no, no); \ + cycle_count += 2; /* Between 1 and 4 cycles? */ \ } \ } \ else \ @@ -612,6 +621,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: \ @@ -649,6 +659,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 \ @@ -666,6 +677,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: \ @@ -1870,6 +1882,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: \ diff --git a/gba_memory.c b/gba_memory.c index 74d22c7..75f15a6 100644 --- a/gba_memory.c +++ b/gba_memory.c @@ -3155,12 +3155,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 */ } } -- cgit v1.2.3 From d0b35e939c1d63c9168c5e3cc64bcab8bfdd2c6b Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Mon, 17 May 2021 13:02:41 +0100 Subject: Add turbo A/B buttons --- input.c | 38 +++++++++++++++ input.h | 12 +++++ libretro.c | 34 ++++++++++++- libretro_core_options.h | 126 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+), 2 deletions(-) diff --git a/input.c b/input.c index 44455d2..9aef248 100644 --- a/input.c +++ b/input.c @@ -24,6 +24,11 @@ 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; @@ -56,6 +61,8 @@ 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; @@ -69,6 +76,9 @@ u32 update_input(void) 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 { @@ -77,7 +87,35 @@ u32 update_input(void) 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); diff --git a/input.h b/input.h index 90fc930..72c7e1e 100644 --- a/input.h +++ b/input.h @@ -61,6 +61,18 @@ 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 28db9dd..5dfe0df 100644 --- a/libretro.c +++ b/libretro.c @@ -841,6 +841,28 @@ 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() @@ -852,6 +874,8 @@ static void set_input_descriptors() { 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" }, @@ -866,6 +890,8 @@ static void set_input_descriptors() { 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" }, @@ -980,6 +1006,11 @@ void retro_unload_game(void) 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) @@ -1052,9 +1083,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_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 }, }; -- cgit v1.2.3 From ea2608812f157007e4b0ba8f86913eb4e780122b Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 19 May 2021 20:09:28 +0200 Subject: Minor optimization --- arm/arm_emit.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arm/arm_emit.h b/arm/arm_emit.h index 4198c7d..22ca763 100644 --- a/arm/arm_emit.h +++ b/arm/arm_emit.h @@ -1657,8 +1657,9 @@ 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) \ - generate_load_pc(reg_a0, (value)); \ - generate_store_reg(reg_a0, reg_rd) + 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; \ -- cgit v1.2.3 From 261b2db9bb65b63d4968f89deecdf92f1975011f Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 19 May 2021 20:09:44 +0200 Subject: Cleanup Makefiles a bit --- Makefile | 13 +++++-------- Makefile.common | 4 ---- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index f4c758f..6edf65c 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 @@ -368,7 +367,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) @@ -444,11 +443,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) @@ -463,6 +457,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) -- cgit v1.2.3 From f19f1695a69b721bd20317b9c5d322f45a214f43 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Thu, 20 May 2021 20:12:00 +0200 Subject: Minor mips asm cleanup and fixes --- psp/mips_emit.h | 3 --- psp/mips_stub.S | 24 ++++++------------------ 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/psp/mips_emit.h b/psp/mips_emit.h index 3f70f13..f2300aa 100644 --- a/psp/mips_emit.h +++ b/psp/mips_emit.h @@ -558,9 +558,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) \ diff --git a/psp/mips_stub.S b/psp/mips_stub.S index 786dc9e..433d904 100644 --- a/psp/mips_stub.S +++ b/psp/mips_stub.S @@ -34,7 +34,6 @@ .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 @@ -283,7 +282,7 @@ return_to_main: lw $fp, 32($sp) lw $ra, 36($sp) jr $ra # Return to main - add $sp, $sp, 48 # Restore stack pointer (delay slot) + addiu $sp, $sp, 48 # Restore stack pointer (delay slot) # Perform an indirect branch. @@ -513,11 +512,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: @@ -538,11 +537,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: @@ -564,22 +563,11 @@ 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 + addiu $sp, $sp, -48 # Store the main thread context sw $s0, 0($sp) sw $s1, 4($sp) sw $s2, 8($sp) -- cgit v1.2.3 From 7a642069e3268b822fe355d9480a501b60dc4728 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 9 Jun 2021 20:21:00 +0200 Subject: Cleanup unused stuff --- cpu.c | 8 -------- gba_memory.c | 35 ----------------------------------- gba_memory.h | 3 --- 3 files changed, 46 deletions(-) diff --git a/cpu.c b/cpu.c index d21eb66..6003849 100644 --- a/cpu.c +++ b/cpu.c @@ -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) \ diff --git a/gba_memory.c b/gba_memory.c index 75f15a6..6bcee36 100644 --- a/gba_memory.c +++ b/gba_memory.c @@ -321,9 +321,6 @@ u32 gamepak_size; dma_transfer_type dma[4]; -u8 *memory_regions[16]; -u32 memory_limits[16]; - typedef struct { u32 page_timestamp; @@ -3196,38 +3193,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); diff --git a/gba_memory.h b/gba_memory.h index 14c8394..5319a30 100644 --- a/gba_memory.h +++ b/gba_memory.h @@ -171,9 +171,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]; -- cgit v1.2.3 From 113863647846008f7e198371bb9fa3aabb432102 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 9 Jun 2021 20:27:12 +0200 Subject: Update libretro.h with the new extensions from upstream --- libretro.h | 312 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) diff --git a/libretro.h b/libretro.h index bda0b77..32aa15f 100644 --- a/libretro.h +++ b/libretro.h @@ -1388,6 +1388,111 @@ enum retro_mod * 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: @@ -2791,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. */ -- cgit v1.2.3 From a160b6de5049cbcdb21d32cecbc4f88e9dc03282 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 16 Jun 2021 19:12:32 +0200 Subject: Minor cleanup in MIPS code --- psp/mips_emit.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/psp/mips_emit.h b/psp/mips_emit.h index f2300aa..1b214fb 100644 --- a/psp/mips_emit.h +++ b/psp/mips_emit.h @@ -201,18 +201,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 \ @@ -2570,12 +2570,12 @@ 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 @@ -2756,9 +2756,8 @@ static void emit_pmemld_stub( mips_emit_seb(reg_rv, reg_rv); } else if (size == 2) { mips_emit_rotr(reg_rv, reg_rv, 8 * alignment); - } else { - mips_emit_nop(); } + generate_function_return_swap_delay(); *tr_ptr = translation_ptr; return; } else { -- cgit v1.2.3 From 34b90277bcba369807a434bde3f770dd401007ac Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 16 Jun 2021 19:35:11 +0200 Subject: Rework patch handlers (MIPS) --- psp/mips_emit.h | 46 +++++++++++++++++++++++++--------------------- psp/mips_stub.S | 9 ++++----- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/psp/mips_emit.h b/psp/mips_emit.h index 1b214fb..53a09a6 100644 --- a/psp/mips_emit.h +++ b/psp/mips_emit.h @@ -58,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, @@ -2581,6 +2579,7 @@ u8 swi_hle_handle[256] = // 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); @@ -3183,14 +3182,14 @@ 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_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) #endif // Stores or byte-accesses do not care about alignment @@ -3200,23 +3199,23 @@ static void emit_phand( } 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(); } @@ -3329,6 +3328,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 433d904..47f219a 100644 --- a/psp/mips_stub.S +++ b/psp/mips_stub.S @@ -35,12 +35,9 @@ .global execute_lsr_flags_reg .global execute_asr_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 @@ -49,7 +46,7 @@ .global memory_map_read .global tmemld .global tmemst -.global tmemst +.global thnjal .global reg .global spsr .global reg_mode @@ -126,7 +123,7 @@ .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 @@ -640,6 +637,8 @@ tmemld: .space 704 tmemst: .space 256 +thnjal: + .space 960 fnptrs: .long update_gba # 0 .long block_lookup_address_arm # 1 -- cgit v1.2.3 From e0a31952dbffd15cd2878ed20142ec41cbd937bb Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Fri, 18 Jun 2021 18:03:47 +0200 Subject: Add preliminary support for non mips32r2 devices This is required in PS2 but could also make older dingux devices run gpsp on retroarch --- Makefile | 7 ++- psp/mips_emit.h | 179 ++++++++++++++++++++++++++++++++++++-------------------- psp/mips_stub.S | 29 ++++++--- 3 files changed, 142 insertions(+), 73 deletions(-) diff --git a/Makefile b/Makefile index 6edf65c..4d75fdd 100644 --- a/Makefile +++ b/Makefile @@ -200,7 +200,7 @@ 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 @@ -375,7 +375,7 @@ 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 += -fno-caller-saves + CFLAGS += -fno-caller-saves -DMIPS_HAS_R2_INSTS HAVE_DYNAREC := 1 CPU_ARCH := mips @@ -393,6 +393,7 @@ else ifeq ($(platform), gcw0) 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 @@ -408,7 +409,7 @@ else ifeq ($(platform), gcw0-odbeta) # 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 += -fno-caller-saves -DMIPS_HAS_R2_INSTS HAVE_DYNAREC := 1 CPU_ARCH := mips diff --git a/psp/mips_emit.h b/psp/mips_emit.h index 53a09a6..679c9e0 100644 --- a/psp/mips_emit.h +++ b/psp/mips_emit.h @@ -791,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 \ @@ -804,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; \ } \ @@ -813,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 \ @@ -827,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 \ @@ -841,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 \ @@ -870,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); \ @@ -892,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; \ @@ -1894,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++) \ { \ @@ -2070,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(); \ @@ -2331,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++) \ { \ @@ -2528,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 @@ -2698,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)); @@ -2735,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); @@ -2750,11 +2805,11 @@ 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); + rotate_right(reg_rv, reg_rv, reg_temp, 8 * alignment); } generate_function_return_swap_delay(); *tr_ptr = translation_ptr; @@ -2770,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 { @@ -2795,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 @@ -2842,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 { @@ -2951,7 +3005,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); @@ -3187,15 +3241,16 @@ static void emit_phand( 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_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 diff --git a/psp/mips_stub.S b/psp/mips_stub.S index 47f219a..48146b3 100644 --- a/psp/mips_stub.S +++ b/psp/mips_stub.S @@ -130,9 +130,25 @@ # 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 @@ -144,10 +160,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 @@ -403,7 +415,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 -- cgit v1.2.3 From f8d4276e12165a2610c87e998a343c02c2904855 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Mon, 21 Jun 2021 19:17:19 +0200 Subject: Add support for mips64n32 This only needs some support to save/load state with 64 bit registers. Since pointers remain 32 bit, no extra changes are needed in the dynarec. Verified with qemu (qemu-mipsn32el) and miniretro. --- Makefile | 10 +++++++++ psp/mips_stub.S | 67 ++++++++++++++++++++++++++++++++++----------------------- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index 4d75fdd..d127e92 100644 --- a/Makefile +++ b/Makefile @@ -379,6 +379,16 @@ else ifeq ($(platform), mips32) HAVE_DYNAREC := 1 CPU_ARCH := mips +# MIPS64 +else ifeq ($(platform), mips64n32) + TARGET := $(TARGET_NAME)_libretro.so + SHARED := -shared -nostdlib -Wl,--version-script=link.T + fpic := -fPIC -DPIC + CFLAGS += -fomit-frame-pointer -ffast-math -march=mips64 -mabi=n32 -mhard-float + CFLAGS += -fno-caller-saves + HAVE_DYNAREC := 1 + CPU_ARCH := mips + # emscripten else ifeq ($(platform), emscripten) TARGET := $(TARGET_NAME)_libretro_$(platform).bc diff --git a/psp/mips_stub.S b/psp/mips_stub.S index 48146b3..59cf2a0 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 @@ -117,6 +129,7 @@ .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) @@ -190,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 @@ -279,20 +292,19 @@ mips_cheat_hook: # 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, 0*SZREG($sp) + REG_L $s1, 1*SZREG($sp) + REG_L $s2, 2*SZREG($sp) + REG_L $s3, 3*SZREG($sp) + REG_L $s4, 4*SZREG($sp) + REG_L $s5, 5*SZREG($sp) + REG_L $s6, 6*SZREG($sp) + REG_L $s7, 7*SZREG($sp) + REG_L $fp, 8*SZREG($sp) + REG_L $ra, 9*SZREG($sp) jr $ra # Return to main - addiu $sp, $sp, 48 # Restore stack pointer (delay slot) - + addiu $sp, $sp, 80 # Restore stack pointer (delay slot) # Perform an indirect branch. @@ -577,20 +589,21 @@ asr_shift_high: # $5: pointer to reg execute_arm_translate_internal: - addiu $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, -80 # Store the main thread context + REG_S $s0, 0*SZREG($sp) + REG_S $s1, 1*SZREG($sp) + REG_S $s2, 2*SZREG($sp) + REG_S $s3, 3*SZREG($sp) + REG_S $s4, 4*SZREG($sp) + REG_S $s5, 5*SZREG($sp) + REG_S $s6, 6*SZREG($sp) + REG_S $s7, 7*SZREG($sp) + REG_S $fp, 8*SZREG($sp) + REG_S $ra, 9*SZREG($sp) move $16, $5 - sw $28, GP_SAVE($16) + REG_S $28, GP_SAVE($16) addu $17, $4, $0 # load cycle counter register -- cgit v1.2.3 From dbf72e95efd507d5a6255c25aee055a0a3c1350e Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Tue, 22 Jun 2021 00:09:44 +0200 Subject: Fix the no-caller-saves bug for MIPS Seems that ABI mandates that we allocate space for arg0..4 even if we do pass them as registers. For some reason write_io_register<> functions write in that stack area (1 word) corrupting the s0 saved register. This seems to be a new gcc behaviour? --- Makefile | 21 ++------------------- psp/mips_stub.S | 44 ++++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 41 deletions(-) diff --git a/Makefile b/Makefile index d127e92..cf0bfd1 100644 --- a/Makefile +++ b/Makefile @@ -375,7 +375,7 @@ 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 += -fno-caller-saves -DMIPS_HAS_R2_INSTS + CFLAGS += -DMIPS_HAS_R2_INSTS HAVE_DYNAREC := 1 CPU_ARCH := mips @@ -385,7 +385,6 @@ else ifeq ($(platform), mips64n32) SHARED := -shared -nostdlib -Wl,--version-script=link.T fpic := -fPIC -DPIC CFLAGS += -fomit-frame-pointer -ffast-math -march=mips64 -mabi=n32 -mhard-float - CFLAGS += -fno-caller-saves HAVE_DYNAREC := 1 CPU_ARCH := mips @@ -394,7 +393,7 @@ else ifeq ($(platform), emscripten) TARGET := $(TARGET_NAME)_libretro_$(platform).bc STATIC_LINKING = 1 -# GCW0 +# GCW0 (OD and OD Beta) else ifeq ($(platform), gcw0) TARGET := $(TARGET_NAME)_libretro.so CC = /opt/gcw0-toolchain/usr/bin/mipsel-linux-gcc @@ -407,22 +406,6 @@ else ifeq ($(platform), gcw0) HAVE_DYNAREC := 1 CPU_ARCH := mips -# GCW0 (OpenDingux Beta) -else ifeq ($(platform), gcw0-odbeta) - 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 - # 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 -DMIPS_HAS_R2_INSTS - HAVE_DYNAREC := 1 - CPU_ARCH := mips - # Windows else TARGET := $(TARGET_NAME)_libretro.dll diff --git a/psp/mips_stub.S b/psp/mips_stub.S index 59cf2a0..7b9bcb0 100644 --- a/psp/mips_stub.S +++ b/psp/mips_stub.S @@ -293,18 +293,18 @@ mips_cheat_hook: # ARM regs must be saved before branching here return_to_main: REG_L $28, GP_SAVE($16) # Restore previous state - REG_L $s0, 0*SZREG($sp) - REG_L $s1, 1*SZREG($sp) - REG_L $s2, 2*SZREG($sp) - REG_L $s3, 3*SZREG($sp) - REG_L $s4, 4*SZREG($sp) - REG_L $s5, 5*SZREG($sp) - REG_L $s6, 6*SZREG($sp) - REG_L $s7, 7*SZREG($sp) - REG_L $fp, 8*SZREG($sp) - REG_L $ra, 9*SZREG($sp) + 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 - addiu $sp, $sp, 80 # Restore stack pointer (delay slot) + addiu $sp, $sp, 112 # Restore stack pointer (delay slot) # Perform an indirect branch. @@ -590,17 +590,17 @@ asr_shift_high: execute_arm_translate_internal: - addiu $sp, $sp, -80 # Store the main thread context - REG_S $s0, 0*SZREG($sp) - REG_S $s1, 1*SZREG($sp) - REG_S $s2, 2*SZREG($sp) - REG_S $s3, 3*SZREG($sp) - REG_S $s4, 4*SZREG($sp) - REG_S $s5, 5*SZREG($sp) - REG_S $s6, 6*SZREG($sp) - REG_S $s7, 7*SZREG($sp) - REG_S $fp, 8*SZREG($sp) - REG_S $ra, 9*SZREG($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 REG_S $28, GP_SAVE($16) -- cgit v1.2.3 From 8739b97b2d5875dbd5306f5eded04a03b84c2160 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Tue, 22 Jun 2021 23:50:07 +0200 Subject: Fix CI for OD beta --- .gitlab-ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e3550f2..fdbedc4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -185,5 +185,3 @@ libretro-build-dingux-odbeta-mips32: extends: - .libretro-dingux-odbeta-mips32-make-default - .core-defs - variables: - platform: gcw0-odbeta -- cgit v1.2.3 From bdf029398070b338e28318d5e1e2418a1815c3a6 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Fri, 25 Jun 2021 00:44:38 +0200 Subject: Remove macros in dma code This reduces code size more than 20% (which is 200-300KB!). DMA handling accounts for less than 0.5% the average emulation runtime which doesn't justify the crazy optimization level that the code has. In fact it's more than likely that the new code runs faster due to less I-cache trashing. --- gba_memory.c | 215 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 105 insertions(+), 110 deletions(-) diff --git a/gba_memory.c b/gba_memory.c index 6bcee36..af94585 100644 --- a/gba_memory.c +++ b/gba_memory.c @@ -2486,19 +2486,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, \ @@ -2650,17 +2637,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]; \ @@ -2669,268 +2663,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. @@ -2959,35 +2954,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; } @@ -3001,35 +2996,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; } @@ -3046,10 +3041,10 @@ cpu_alert_type dma_transfer(dma_transfer_type *dma) 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. -- cgit v1.2.3 From 8dbf5f6c17e3d217877119620e5bbfeba05abd7a Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Sun, 27 Jun 2021 01:16:28 +0200 Subject: Enable big-endian devices: gc/wii This patch adds big-endian compatibility in gpsp (in general but only for the interpreter). There's no performance hit for little-endian platforms (should be a no-op) and only add a small overhead in memory accesses for big-endian platforms. Most memory accesses are wrapped with a byteswap instruction and I/O reg accesses are also rewired for proper access (using macros). Video rendering has been fixed to also do byteswaps but there's a couple of games and rendering modes that still seem broken (but they amount to less than 20 games in my tests with 1K ROMs). This also adds build rules and CI for NGC/WII/WIIU (untested) --- .gitlab-ci.yml | 30 +++++++ Makefile | 8 ++ cheats.c | 2 +- common.h | 16 ++++ cpu.c | 26 +++--- gba_memory.c | 199 +++++++++++++++++++++--------------------- gba_memory.h | 13 +++ input.c | 4 +- main.c | 22 ++--- sound.c | 4 +- video.c | 267 ++++++++++++++++++++++++++++----------------------------- 11 files changed, 326 insertions(+), 265 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fdbedc4..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: diff --git a/Makefile b/Makefile index cf0bfd1..5f7afff 100644 --- a/Makefile +++ b/Makefile @@ -195,6 +195,14 @@ 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 diff --git a/cheats.c b/cheats.c index 17556ca..3594730 100644 --- a/cheats.c +++ b/cheats.c @@ -190,7 +190,7 @@ void process_cheats(void) if(!cheats[i].cheat_active) continue; - process_cheat_codebreaker(&cheats[i], 0x3ff ^ io_registers[REG_P1]); + process_cheat_codebreaker(&cheats[i], 0x3ff ^ read_ioreg(REG_P1)); } } diff --git a/common.h b/common.h index ef6724a..ff4d522 100644 --- a/common.h +++ b/common.h @@ -124,6 +124,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 #include #include diff --git a/cpu.c b/cpu.c index 6003849..873a5e3 100644 --- a/cpu.c +++ b/cpu.c @@ -721,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]; \ @@ -945,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) \ { \ @@ -964,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 \ { \ @@ -984,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 \ { \ @@ -1018,7 +1018,7 @@ const u32 psr_masks[16] = } \ if(_address < 0x10000000 && map) \ { \ - dest = address32(map, _address & 0x7FFF); \ + dest = readaddress32(map, _address & 0x7FFF); \ } \ else \ { \ @@ -1123,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) \ @@ -1601,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,7 +1681,7 @@ arm_loop: 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) @@ -3256,7 +3256,7 @@ thumb_loop: using_instruction(thumb); check_pc_region(); pc &= ~0x01; - opcode = address16(pc_address_block, (pc & 0x7FFF)); + opcode = readaddress16(pc_address_block, (pc & 0x7FFF)); switch((opcode >> 8) & 0xFF) { diff --git a/gba_memory.c b/gba_memory.c index af94585..4376cf8 100644 --- a/gba_memory.c +++ b/gba_memory.c @@ -35,7 +35,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) \ @@ -56,7 +56,7 @@ } \ \ gbc_sound_update = 1; \ - address16(io_registers, address) = value; \ + address16(io_registers, address) = eswap16(value); \ } \ #define gbc_sound_tone_control_sweep() \ @@ -68,7 +68,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() \ @@ -80,7 +80,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 }; @@ -94,7 +94,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() \ @@ -110,7 +110,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() \ @@ -141,7 +141,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) @@ -156,7 +156,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() \ @@ -175,7 +175,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) @@ -193,8 +193,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) \ @@ -238,7 +238,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; @@ -266,7 +266,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 @@ -458,7 +458,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 { @@ -508,10 +508,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)) \ @@ -580,29 +580,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: \ @@ -611,12 +611,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: \ @@ -660,12 +660,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; @@ -686,7 +686,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)) @@ -708,7 +708,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); } @@ -717,7 +717,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; @@ -731,10 +731,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) { @@ -743,7 +743,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; @@ -768,28 +768,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 @@ -797,28 +797,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 @@ -826,28 +826,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 @@ -855,28 +855,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 @@ -1160,18 +1160,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 @@ -1182,26 +1181,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 @@ -1209,26 +1208,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 @@ -1313,7 +1312,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 @@ -1382,7 +1381,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 @@ -1399,7 +1398,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; } @@ -1414,25 +1413,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 @@ -1468,7 +1467,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; \ } \ @@ -1478,11 +1477,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; \ } \ @@ -1616,13 +1615,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...) @@ -1682,7 +1681,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) { @@ -1897,12 +1896,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: \ @@ -1926,7 +1925,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: \ @@ -2544,26 +2543,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.. @@ -2575,17 +2574,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) \ @@ -2594,7 +2596,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) \ @@ -3034,8 +3037,8 @@ 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) @@ -3208,13 +3211,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 5319a30..0f9dc3a 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, diff --git a/input.c b/input.c index 9aef248..e030596 100644 --- a/input.c +++ b/input.c @@ -38,7 +38,7 @@ 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) { @@ -121,7 +121,7 @@ u32 update_input(void) 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) diff --git a/main.c b/main.c index 260edd5..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++) { @@ -251,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/sound.c b/sound.c index 10a3261..bc88fff 100644 --- a/sound.c +++ b/sound.c @@ -437,7 +437,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; @@ -521,7 +521,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 = 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) \ -- cgit v1.2.3 From 836e51b694f33d864cf4962d1dd3718bb56803c6 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 30 Jun 2021 00:29:21 +0200 Subject: Fix some UB behaviour --- cpu.c | 2 +- sound.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpu.c b/cpu.c index 873a5e3..60ff3bc 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() \ diff --git a/sound.c b/sound.c index bc88fff..76c3525 100644 --- a/sound.c +++ b/sound.c @@ -85,9 +85,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) { @@ -655,7 +655,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; } audio_batch_cb(stream_base, 256); -- cgit v1.2.3 From 3d874ec5e3d5675ae9513264d857a3c6c9d2417c Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Thu, 1 Jul 2021 12:04:48 +0200 Subject: Add palette conversion routine for non-R2 MIPS Gated MIPS_HAS_R2_INSTS not used at the moment. Tested with qemu. --- psp/mips_emit.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/psp/mips_emit.h b/psp/mips_emit.h index 679c9e0..7f51b8f 100644 --- a/psp/mips_emit.h +++ b/psp/mips_emit.h @@ -2969,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 -- cgit v1.2.3