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