diff --git a/arm/arm_stub.S b/arm/arm_stub.S index e8f7316..f5fceb0 100644 --- a/arm/arm_stub.S +++ b/arm/arm_stub.S @@ -4,7 +4,6 @@ .globl invalidate_cache_region .globl memory_map_read -.globl memory_map_write .globl reg .globl palette_ram .globl palette_ram_converted @@ -533,31 +532,6 @@ return_to_main: bx lr -@ Write out to memory. - -@ Input: -@ r0: address -@ r1: value -@ r2: current pc - -#define execute_store_body(store_type, store_op) ;\ - save_flags() ;\ - str lr, [reg_base, #REG_SAVE3] /* save lr */;\ - tst r0, #0xF0000000 /* make sure address is in range */;\ - bne ext_store_u##store_type /* if not do ext store */;\ - ;\ - ldr r2, =memory_map_write /* r2 = memory_map_write */;\ - mov lr, r0, lsr #15 /* lr = page index of address */;\ - ldr r2, [r2, lr, lsl #2] /* r2 = memory page */;\ - ;\ - cmp r2, #0 /* see if map is ext */;\ - beq ext_store_u##store_type /* if so do ext store */;\ - ;\ - mov r0, r0, lsl #17 /* isolate bottom 15 bits in top */;\ - mov r0, r0, lsr #17 /* like performing and 0x7FFF */;\ - store_op r1, [r2, r0] /* store result */;\ - - #define store_align_8() ;\ and r1, r1, #0xff ;\ @@ -568,6 +542,75 @@ return_to_main: #define store_align_32() ;\ bic r0, r0, #0x03 ;\ +#define mask_addr_8(nbits) ;\ + mov r0, r0, lsl #(32 - nbits) /* isolate bottom n bits in top */;\ + mov r0, r0, lsr #(32 - nbits) /* high bits are now clear */;\ + +#define mask_addr_16(nbits) ;\ + mov r0, r0, lsl #(32 - nbits) /* isolate bottom n bits in top */;\ + mov r0, r0, lsr #(32 - nbits + 1) /* high bits are now clear */;\ + mov r0, r0, lsl #1 /* LSB is also zero */;\ + +#define mask_addr_32(nbits) ;\ + mov r0, r0, lsl #(32 - nbits) /* isolate bottom n bits in top */;\ + mov r0, r0, lsr #(32 - nbits + 2) /* high bits are now clear */;\ + mov r0, r0, lsl #2 /* 2 LSB are also zero */;\ + +@ Vram, OAM and palette memories can only be accessed at a 16 bit boundary +#define mask_addr_bus16_32(nbits) mask_addr_32(nbits) +#define mask_addr_bus16_16(nbits) mask_addr_16(nbits) +#define mask_addr_bus16_8(nbits) \ + mask_addr_16(nbits) \ + extract_u16(r1, r1) + + +@ Write out to memory. + +@ Input: +@ r0: address +@ r1: value +@ r2: current pc +@ +@ The instruction at LR is not an inst but a u32 data that contains the PC +@ Used for SMC. That's why return is essentially `pc = lr + 4` + +#define execute_store_body(store_type, store_op) ;\ + save_flags() ;\ + str lr, [reg_base, #REG_SAVE3] /* save lr */;\ + str r4, [reg_base, #REG_SAVE2] /* save r4 */;\ + tst r0, #0xF0000000 /* make sure address is in range */;\ + bne ext_store_u##store_type /* if not do ext store */;\ + ;\ + ldr lr, =ptr_tbl_##store_type /* lr = ptr table */;\ + mov r4, r0, lsr #24 /* r4 = region number */;\ + ldr lr, [lr, r4, lsl #2] /* lr = function pointer */;\ + ldr r4, [reg_base, #REG_SAVE2] /* restore r4 */;\ + bx lr /* jump to handler */;\ + ;\ +ptr_tbl_##store_type: ;\ + .word ext_store_ignore /* 0x00: BIOS, ignore */;\ + .word ext_store_ignore /* 0x01: ignore */;\ + .word ext_store_ewram_u##store_type /* 0x02: ewram */;\ + .word ext_store_iwram_u##store_type /* 0x03: iwram */;\ + .word ext_store_u##store_type /* 0x04: I/O regs */;\ + .word ext_store_u##store_type /* 0x05: palette RAM */;\ + .word ext_store_vram_u##store_type /* 0x06: vram */;\ + .word ext_store_u##store_type /* 0x07: oam ram */;\ + .word ext_store_u##store_type /* 0x08: gamepak: ignore */;\ + .word ext_store_u##store_type /* 0x09: gamepak: ignore */;\ + .word ext_store_u##store_type /* 0x0A: gamepak: ignore */;\ + .word ext_store_u##store_type /* 0x0B: gamepak: ignore */;\ + .word ext_store_u##store_type /* 0x0C: gamepak: ignore */;\ + .word ext_store_u##store_type /* 0x0D: EEPROM */;\ + .word ext_store_u##store_type /* 0x0E: backup */;\ + .word ext_store_ignore /* 0x0F: ignore */;\ + +@ for ignored areas, just return +ext_store_ignore: + ldr lr, [reg_base, #REG_SAVE3] @ pop lr off of stack + restore_flags() + add pc, lr, #4 @ return + #define execute_store_builder(store_type, store_op, load_op) ;\ ;\ @@ -577,20 +620,6 @@ return_to_main: execute_store_u##store_type: ;\ _execute_store_u##store_type: ;\ execute_store_body(store_type, store_op) ;\ - sub r2, r2, #0x8000 /* Pointer to code status data */;\ - load_op r0, [r2, r0] /* check code flag */;\ - ;\ - cmp r0, #0 /* see if it's not 0 */;\ - bne 2f /* if so perform smc write */;\ - ldr lr, [reg_base, #REG_SAVE3] /* restore lr */;\ - restore_flags() ;\ - add pc, lr, #4 /* return */;\ - ;\ -2: ;\ - ldr lr, [reg_base, #REG_SAVE3] /* restore lr */;\ - ldr r0, [lr] /* load PC */;\ - str r0, [reg_base, #REG_PC] /* write out PC */;\ - b smc_write /* perform smc write */;\ ;\ ext_store_u##store_type: ;\ ldr lr, [reg_base, #REG_SAVE3] /* pop lr off of stack */;\ @@ -599,11 +628,53 @@ ext_store_u##store_type: ;\ store_align_##store_type() ;\ call_c_function(write_memory##store_type) ;\ b write_epilogue /* handle additional write stuff */;\ + ;\ +ext_store_iwram_u##store_type: ;\ + mask_addr_##store_type(15) /* Mask to mirror memory (+align)*/;\ + ldr r2, =(iwram+0x8000) /* r2 = iwram base */;\ + store_op r1, [r0, r2] /* store data */;\ + sub r2, r2, #0x8000 /* r2 = iwram smc base */;\ + load_op r1, [r0, r2] /* r1 = SMC sentinel */;\ + cmp r1, #0 /* see if it's not 0 */;\ + bne 3f /* if so perform smc write */;\ + ldr lr, [reg_base, #REG_SAVE3] /* pop lr off of stack */;\ + restore_flags() ;\ + add pc, lr, #4 /* return */;\ + ;\ +ext_store_ewram_u##store_type: ;\ + mask_addr_##store_type(18) /* Mask to mirror memory (+align)*/;\ + ldr r2, =(ewram) /* r2 = ewram base */;\ + store_op r1, [r0, r2] /* store data */;\ + add r2, r2, #0x40000 /* r2 = ewram smc base */;\ + load_op r1, [r0, r2] /* r1 = SMC sentinel */;\ + cmp r1, #0 /* see if it's not 0 */;\ + bne 3f /* if so perform smc write */;\ + ldr lr, [reg_base, #REG_SAVE3] /* pop lr off of stack */;\ + restore_flags() ;\ + add pc, lr, #4 /* return */;\ + ;\ +ext_store_vram_u##store_type: ;\ + mask_addr_bus16_##store_type(17) /* Mask to mirror memory (+align)*/;\ + cmp r0, #0x18000 /* Check if exceeds 96KB */;\ + subcs r0, r0, #0x8000 /* Mirror to the last bank */;\ + ldr r2, =(vram) /* r2 = vram base */;\ + store_op r1, [r0, r2] /* store data */;\ + ldr lr, [reg_base, #REG_SAVE3] /* pop lr off of stack */;\ + restore_flags() ;\ + add pc, lr, #4 /* return */;\ + ;\ +3: ;\ + ldr lr, [reg_base, #REG_SAVE3] /* restore lr */;\ + ldr r0, [lr] /* load PC */;\ + str r0, [reg_base, #REG_PC] /* write out PC */;\ + b smc_write /* perform smc write */;\ + execute_store_builder(8, strb, ldrb) execute_store_builder(16, strh, ldrh) execute_store_builder(32, str, ldr) +@ This is a store that is executed in a strm case (so no SMC checks in-between) .globl execute_store_u32_safe .globl _execute_store_u32_safe @@ -619,6 +690,28 @@ ext_store_u32_safe: restore_flags() bx lr @ Return +ext_store_iwram_u32_safe: + mask_addr_8(15) @ Mask to mirror memory (no need to align!) + ldr r2, =(iwram+0x8000) @ r2 = iwram base + str r1, [r0, r2] @ store data + restore_flags() + ldr pc, [reg_base, #REG_SAVE3] @ return + +ext_store_ewram_u32_safe: + mask_addr_8(18) @ Mask to mirror memory (no need to align!) + ldr r2, =(ewram) @ r2 = ewram base + str r1, [r0, r2] @ store data + restore_flags() + ldr pc, [reg_base, #REG_SAVE3] @ return + +ext_store_vram_u32_safe: + mask_addr_8(17) @ Mask to mirror memory (no need to align!) + ldr r2, =(vram) @ r2 = vram base + cmp r0, #0x18000 @ Check if exceeds 96KB + subcs r0, r0, #0x8000 @ Mirror to the last bank + str r1, [r0, r2] @ store data + restore_flags() + ldr pc, [reg_base, #REG_SAVE3] @ return write_epilogue: cmp r0, #0 @ check if the write rose an alert @@ -756,6 +849,7 @@ ext_load_##load_type: ;\ restore_flags() ;\ add pc, lr, #4 /* return */;\ +.pool execute_load_builder(u8, 8, ldrneb, #0xF0000000) execute_load_builder(s8, 8, ldrnesb, #0xF0000000) @@ -763,14 +857,10 @@ execute_load_builder(u16, 16, ldrneh, #0xF0000001) execute_load_builder(s16, 16_signed, ldrnesh, #0xF0000001) execute_load_builder(u32, 32, ldrne, #0xF0000000) -.pool - .data memory_map_read: .space 0x8000 -memory_map_write: - .space 0x8000 palette_ram: .space 0x400 palette_ram_converted: diff --git a/cpu.c b/cpu.c index 11c947f..ea0d69e 100644 --- a/cpu.c +++ b/cpu.c @@ -1003,7 +1003,6 @@ const u32 psr_masks[16] = #define fast_write_memory(size, type, address, value) \ { \ - u8 *map; \ u32 _address = (address) & ~(aligned_address_mask##size & 0x03); \ if(_address < 0x10000000) \ { \ @@ -1011,17 +1010,9 @@ const u32 psr_masks[16] = memory_writes_##type++; \ } \ \ - if(((_address & aligned_address_mask##size) == 0) && \ - (map = memory_map_write[_address >> 15])) \ - { \ - *((type *)((u8 *)map + (_address & 0x7FFF))) = value; \ - } \ - else \ - { \ - cpu_alert = write_memory##size(_address, value); \ - if(cpu_alert) \ - goto alert; \ - } \ + cpu_alert = write_memory##size(_address, value); \ + if(cpu_alert) \ + goto alert; \ } \ #define load_aligned32(address, dest) \ @@ -1046,22 +1037,14 @@ const u32 psr_masks[16] = #define store_aligned32(address, value) \ { \ u32 _address = address; \ - u8 *map = memory_map_write[_address >> 15]; \ if(_address < 0x10000000) \ { \ memory_region_access_write_u32[_address >> 24]++; \ memory_writes_u32++; \ } \ - if(map) \ - { \ - address32(map, _address & 0x7FFF) = value; \ - } \ - else \ - { \ - cpu_alert = write_memory32(_address, value); \ - if(cpu_alert) \ - goto alert; \ - } \ + cpu_alert = write_memory32(_address, value); \ + if(cpu_alert) \ + goto alert; \ } \ #define load_memory_u8(address, dest) \ @@ -1647,7 +1630,6 @@ void raise_interrupt(irq_type irq_raised) #ifndef HAVE_DYNAREC u8 *memory_map_read [8 * 1024]; -u8 *memory_map_write[8 * 1024]; u16 palette_ram[512]; u16 palette_ram_converted[512]; #endif diff --git a/cpu.h b/cpu.h index cde7b2f..faa3bc1 100644 --- a/cpu.h +++ b/cpu.h @@ -155,11 +155,7 @@ extern u8 *ram_translation_ptr; #define MAX_TRANSLATION_GATES 8 extern u32 idle_loop_target_pc; -extern u32 force_pc_update_target; extern u32 iwram_stack_optimize; -extern u32 allow_smc_ram_u8; -extern u32 allow_smc_ram_u16; -extern u32 allow_smc_ram_u32; extern u32 direct_map_vram; extern u32 translation_gate_targets; extern u32 translation_gate_target_pc[MAX_TRANSLATION_GATES]; diff --git a/cpu_threaded.c b/cpu_threaded.c index 519d7f0..555b9c6 100644 --- a/cpu_threaded.c +++ b/cpu_threaded.c @@ -76,12 +76,6 @@ u32 ewram_code_max = 0xFFFFFFFF; u32 *rom_branch_hash[ROM_BRANCH_HASH_SIZE]; -// Default -u32 force_pc_update_target = 0xFFFFFFFF; -u32 allow_smc_ram_u8 = 1; -u32 allow_smc_ram_u16 = 1; -u32 allow_smc_ram_u32 = 1; - typedef struct { u8 *block_offset; @@ -2813,7 +2807,7 @@ u8 function_cc *block_lookup_address_##type(u32 pc) \ switch(pc >> 24) \ { \ case 0x2: \ - location = (u16 *)(ewram + (pc & 0x7FFF) + ((pc & 0x38000) * 2)); \ + location = (u16 *)(ewram + (pc & 0x3FFFF) + 0x40000); \ block_lookup_translate(type, ram, 1); \ break; \ \ @@ -3119,18 +3113,22 @@ block_lookup_address_builder(dual); block_data_type block_data[MAX_BLOCK_SIZE]; block_exit_type block_exits[MAX_EXITS]; -#define smc_write_arm_yes() \ - if(address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \ +#define smc_write_arm_yes() { \ + int offset = (pc < 0x03000000) ? 0x40000 : -0x8000; \ + if(address32(pc_address_block, (block_end_pc & 0x7FFF) + offset) == 0) \ { \ - address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = \ + address32(pc_address_block, (block_end_pc & 0x7FFF) + offset) = \ 0xFFFFFFFF; \ } \ +} -#define smc_write_thumb_yes() \ - if(address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \ +#define smc_write_thumb_yes() { \ + int offset = (pc < 0x03000000) ? 0x40000 : -0x8000; \ + if(address16(pc_address_block, (block_end_pc & 0x7FFF) + offset) == 0) \ { \ - address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = 0xFFFF; \ + address16(pc_address_block, (block_end_pc & 0x7FFF) + offset) = 0xFFFF; \ } \ +} #define smc_write_arm_no() \ @@ -3428,7 +3426,6 @@ s32 translate_block_thumb(u32 pc, translation_region_type u32 opcode = 0; u32 last_opcode; u32 condition; - u32 last_condition; u32 pc_region = (pc >> 15); u32 new_pc_region; u8 *pc_address_block = memory_map_read[pc_region]; @@ -3514,8 +3511,6 @@ s32 translate_block_thumb(u32 pc, translation_region_type block_exit_position = 0; block_data_position = 0; - last_condition = 0x0E; - while(pc != block_end_pc) { block_data[block_data_position].block_offset = translation_ptr; @@ -3627,13 +3622,16 @@ s32 translate_block_thumb(u32 pc, translation_region_type void flush_translation_cache_ram(void) { flush_ram_count++; -/* printf("ram flush %d (pc %x), %x to %x, %x to %x\n", + /*printf("ram flush %d (pc %x), %x to %x, %x to %x\n", flush_ram_count, reg[REG_PC], iwram_code_min, iwram_code_max, - ewram_code_min, ewram_code_max); */ + ewram_code_min, ewram_code_max);*/ last_ram_translation_ptr = ram_translation_cache; ram_translation_ptr = ram_translation_cache; ram_block_tag_top = 0x0101; + + // Proceed to clean the SMC area if needed + // (also try to memset as little as possible for performance) if(iwram_code_min != 0xFFFFFFFF) { iwram_code_min &= 0x7FFF; @@ -3643,33 +3641,9 @@ void flush_translation_cache_ram(void) if(ewram_code_min != 0xFFFFFFFF) { - u32 ewram_code_min_page; - u32 ewram_code_max_page; - u32 ewram_code_min_offset; - u32 ewram_code_max_offset; - u32 i; - ewram_code_min &= 0x3FFFF; ewram_code_max &= 0x3FFFF; - - ewram_code_min_page = ewram_code_min >> 15; - ewram_code_max_page = ewram_code_max >> 15; - ewram_code_min_offset = ewram_code_min & 0x7FFF; - ewram_code_max_offset = ewram_code_max & 0x7FFF; - - if(ewram_code_min_page == ewram_code_max_page) - { - memset(ewram + (ewram_code_min_page * 0x10000) + - ewram_code_min_offset, 0, - ewram_code_max_offset - ewram_code_min_offset); - } - else - { - for(i = ewram_code_min_page + 1; i < ewram_code_max_page; i++) - memset(ewram + (i * 0x10000), 0, 0x8000); - - memset(ewram, 0, ewram_code_max_offset); - } + memset(&ewram[0x40000 + ewram_code_min], 0, ewram_code_max - ewram_code_min); } iwram_code_min = 0xFFFFFFFF; diff --git a/gba_memory.c b/gba_memory.c index 948bcc5..a51f183 100644 --- a/gba_memory.c +++ b/gba_memory.c @@ -596,8 +596,7 @@ u32 function_cc read_eeprom(void) \ case 0x02: \ /* external work RAM */ \ - address = (address & 0x7FFF) + ((address & 0x38000) * 2) + 0x8000; \ - value = address##type(ewram, address); \ + value = address##type(ewram, (address & 0x3FFFF)); \ break; \ \ case 0x03: \ @@ -1907,8 +1906,7 @@ void function_cc write_rtc(u32 address, u32 value) { \ case 0x02: \ /* external work RAM */ \ - address = (address & 0x7FFF) + ((address & 0x38000) * 2) + 0x8000; \ - address##type(ewram, address) = value; \ + address##type(ewram, (address & 0x3FFFF)) = value; \ break; \ \ case 0x03: \ @@ -2454,7 +2452,7 @@ s32 load_bios(char *name) // DMA memory regions can be one of the following: // IWRAM - 32kb offset from the contiguous iwram region. -// EWRAM - like segmented but with self modifying code check. +// EWRAM - also contiguous but with self modifying code check mirror. // VRAM - 96kb offset from the contiguous vram region, should take care // Palette RAM - Converts palette entries when written to. // OAM RAM - Sets OAM modified flag to true. @@ -2527,11 +2525,8 @@ dma_region_type dma_region_map[16] = #define dma_vars_iwram(type) \ dma_smc_vars_##type() \ -#define dma_vars_vram(type) \ - -#define dma_vars_palette_ram(type) \ - -#define dma_oam_ram_src() \ +#define dma_vars_ewram(type) \ + dma_smc_vars_##type() #define dma_oam_ram_dest() \ oam_update = 1 \ @@ -2539,14 +2534,17 @@ dma_region_type dma_region_map[16] = #define dma_vars_oam_ram(type) \ dma_oam_ram_##type() \ -#define dma_vars_io(type) \ +#define dma_vars_io(type) +#define dma_vars_vram(type) +#define dma_vars_palette_ram(type) +#define dma_vars_bios(type) +#define dma_vars_ext(type) + +#define dma_oam_ram_src() #define dma_segmented_load_src() \ memory_map_read[src_current_region] \ -#define dma_segmented_load_dest() \ - memory_map_write[dest_current_region] \ - #define dma_vars_gamepak(type) \ u32 type##_new_region; \ u32 type##_current_region = type##_ptr >> 15; \ @@ -2558,24 +2556,6 @@ dma_region_type dma_region_map[16] = type##_address_block = load_gamepak_page(type##_current_region & 0x3FF); \ } \ -#define dma_vars_ewram(type) \ - dma_smc_vars_##type(); \ - u32 type##_new_region; \ - u32 type##_current_region = type##_ptr >> 15; \ - u8 *type##_address_block = dma_segmented_load_##type() \ - -#define dma_vars_bios(type) \ - -#define dma_vars_ext(type) \ - -#define dma_ewram_check_region(type) \ - type##_new_region = (type##_ptr >> 15); \ - if(type##_new_region != type##_current_region) \ - { \ - type##_current_region = type##_new_region; \ - type##_address_block = dma_segmented_load_##type(); \ - } \ - #define dma_gamepak_check_region(type) \ type##_new_region = (type##_ptr >> 15); \ if(type##_new_region != type##_current_region) \ @@ -2605,9 +2585,7 @@ dma_region_type dma_region_map[16] = read_value = address##transfer_size(palette_ram, type##_ptr & 0x3FF) \ #define dma_read_ewram(type, transfer_size) \ - dma_ewram_check_region(type); \ - read_value = address##transfer_size(type##_address_block, \ - type##_ptr & 0x7FFF) \ + read_value = address##transfer_size(ewram, type##_ptr & 0x3FFFF) \ #define dma_read_gamepak(type, transfer_size) \ dma_gamepak_check_region(type); \ @@ -2642,12 +2620,9 @@ dma_region_type dma_region_map[16] = write_memory##transfer_size(type##_ptr, read_value) \ #define dma_write_ewram(type, transfer_size) \ - dma_ewram_check_region(type); \ - \ - address##transfer_size(type##_address_block, type##_ptr & 0x7FFF) = \ - read_value; \ - smc_trigger |= address##transfer_size(type##_address_block, \ - (type##_ptr & 0x7FFF) - 0x8000) \ + address##transfer_size(ewram, type##_ptr & 0x3FFFF) = read_value; \ + smc_trigger |= address##transfer_size(ewram, \ + (type##_ptr & 0x3FFFF) + 0x40000) \ #define dma_epilogue_iwram() \ if(smc_trigger) \ @@ -3105,14 +3080,6 @@ cpu_alert_type dma_transfer(dma_transfer_type *dma) map_offset++) \ memory_map_##type[map_offset] = NULL; \ -#define map_ram_region(type, start, end, mirror_blocks, region) \ - for(map_offset = (start) / 0x8000; map_offset < \ - ((end) / 0x8000); map_offset++) \ - { \ - memory_map_##type[map_offset] = \ - ((u8 *)region) + ((map_offset % mirror_blocks) * 0x10000) + 0x8000; \ - } \ - #define map_vram(type) \ for(map_offset = 0x6000000 / 0x8000; map_offset < (0x7000000 / 0x8000); \ map_offset += 4) \ @@ -3274,8 +3241,8 @@ void init_memory(void) // 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); - map_ram_region(read, 0x2000000, 0x3000000, 8, ewram); - map_ram_region(read, 0x3000000, 0x4000000, 1, iwram); + map_region(read, 0x2000000, 0x3000000, 8, ewram); + map_region(read, 0x3000000, 0x4000000, 1, &iwram[0x8000]); map_region(read, 0x4000000, 0x5000000, 1, io_registers); map_null(read, 0x5000000, 0x6000000); map_null(read, 0x6000000, 0x7000000); @@ -3284,45 +3251,12 @@ void init_memory(void) init_memory_gamepak(); map_null(read, 0xE000000, 0x10000000); - // Fill memory map regions, areas marked as NULL must be checked directly - map_null(write, 0x0000000, 0x2000000); - map_ram_region(write, 0x2000000, 0x3000000, 8, ewram); - map_ram_region(write, 0x3000000, 0x4000000, 1, iwram); - map_null(write, 0x4000000, 0x5000000); - map_null(write, 0x5000000, 0x6000000); - - // The problem here is that the current method of handling self-modifying code - // requires writeable memory to be proceeded by 32KB SMC data areas or be - // indirectly writeable. It's possible to get around this if you turn off the SMC - // check altogether, but this will make a good number of ROMs crash (perhaps most - // of the ones that actually need it? This has yet to be determined). - - // This is because VRAM cannot be efficiently made incontiguous, and still allow - // the renderer to work as efficiently. It would, at the very least, require a - // lot of hacking of the renderer which I'm not prepared to do. - // TODO(davidgfnet): add SMC VRAM detection - - // However, it IS possible to directly map the first page no matter what because - // there's 32kb of blank stuff sitting beneath it. - if(direct_map_vram) - { - map_vram(write); - } - else - { - map_null(write, 0x6000000, 0x7000000); - } - - map_null(write, 0x7000000, 0x8000000); - map_null(write, 0x8000000, 0xE000000); - map_null(write, 0xE000000, 0x10000000); - - memset(io_registers, 0, 0x8000); - memset(oam_ram, 0, 0x400); - memset(palette_ram, 0, 0x400); - memset(iwram, 0, 0x10000); - memset(ewram, 0, 0x80000); - memset(vram, 0, 0x18000); + memset(io_registers, 0, sizeof(io_registers)); + memset(oam_ram, 0, sizeof(oam_ram)); + memset(palette_ram, 0, sizeof(palette_ram)); + memset(iwram, 0, sizeof(iwram)); + memset(ewram, 0, sizeof(ewram)); + memset(vram, 0, sizeof(vram)); io_registers[REG_DISPCNT] = 0x80; io_registers[REG_P1] = 0x3FF; @@ -3426,8 +3360,6 @@ void gba_save_state(void* dst) #define memory_savestate_builder(type) \ void memory_##type##_savestate(void) \ { \ - u32 i; \ - \ state_mem_##type##_variable(backup_type); \ state_mem_##type##_variable(sram_size); \ state_mem_##type##_variable(flash_mode); \ @@ -3453,10 +3385,7 @@ void memory_##type##_savestate(void) \ state_mem_##type##_array(dma); \ \ state_mem_##type(iwram + 0x8000, 0x8000); \ - for(i = 0; i < 8; i++) \ - { \ - state_mem_##type(ewram + (i * 0x10000) + 0x8000, 0x8000); \ - } \ + state_mem_##type(ewram, 0x40000); \ state_mem_##type(vram, 0x18000); \ state_mem_##type(oam_ram, 0x400); \ state_mem_##type(palette_ram, 0x400); \ diff --git a/gba_memory.h b/gba_memory.h index eaa5bab..14c8394 100644 --- a/gba_memory.h +++ b/gba_memory.h @@ -214,7 +214,6 @@ extern u8 ewram[1024 * 256 * 2]; extern u8 iwram[1024 * 32 * 2]; extern u8 *memory_map_read[8 * 1024]; -extern u8 *memory_map_write[8 * 1024]; extern u32 reg[64]; diff --git a/libretro.c b/libretro.c index 334864c..d94ddcb 100644 --- a/libretro.c +++ b/libretro.c @@ -809,15 +809,8 @@ static void set_memory_descriptors(void) { const uint64_t mem = RETRO_MEMORY_SYSTEM_RAM; struct retro_memory_descriptor desc[9] = { - { mem, iwram, 0x00000 + 0x8000, 0x3000000, 0, 0, 0x8000, NULL }, - { mem, ewram, 0x00000 + 0x8000, 0x2000000, 0, 0, 0x8000, NULL }, - { mem, ewram, 0x10000 + 0x8000, 0x2008000, 0, 0, 0x8000, NULL }, - { mem, ewram, 0x20000 + 0x8000, 0x2010000, 0, 0, 0x8000, NULL }, - { mem, ewram, 0x30000 + 0x8000, 0x2018000, 0, 0, 0x8000, NULL }, - { mem, ewram, 0x40000 + 0x8000, 0x2020000, 0, 0, 0x8000, NULL }, - { mem, ewram, 0x50000 + 0x8000, 0x2028000, 0, 0, 0x8000, NULL }, - { mem, ewram, 0x60000 + 0x8000, 0x2030000, 0, 0, 0x8000, NULL }, - { mem, ewram, 0x70000 + 0x8000, 0x2038000, 0, 0, 0x8000, NULL } + { mem, iwram, 0x00000 + 0x8000, 0x3000000, 0, 0, 0x8000, NULL }, + { mem, ewram, 0x00000, 0x2000000, 0, 0, 0x40000, NULL }, }; struct retro_memory_map retromap = { desc, diff --git a/psp/mips_emit.h b/psp/mips_emit.h index 8d1d8d8..b75f7f5 100644 --- a/psp/mips_emit.h +++ b/psp/mips_emit.h @@ -1010,47 +1010,10 @@ u32 generate_load_rm_sh_##flags_op(u32 rm) \ { \ u32 _address = (u32)(address); \ u32 _address_hi = (_address + 0x8000) >> 16; \ - generate_load_imm(ireg, address); \ mips_emit_lui(ireg, _address_hi >> 16) \ generate_load_memory_##type(ireg, _address - (_address_hi << 16)); \ } \ -#define generate_known_address_load_builder(type) \ - u32 generate_known_address_load_##type(u32 rd, u32 address) \ - { \ - switch(address >> 24) \ - { \ - /* Read from the BIOS ROM, can be converted to an immediate load. \ - Only really possible to do this from the BIOS but should be okay \ - to allow it everywhere */ \ - case 0x00: \ - u32 imm = read_memory_constant_##type(address); \ - generate_load_imm(arm_to_mips_reg[rd], imm); \ - return 1; \ - \ - /* Read from RAM, can be converted to a load */ \ - case 0x02: \ - generate_load_memory(type, arm_to_mips_reg[rd], (u8 *)ewram + \ - (address & 0x7FFF) + ((address & 0x38000) * 2) + 0x8000); \ - return 1; \ - \ - case 0x03: \ - generate_load_memory(type, arm_to_mips_reg[rd], (u8 *)iwram + \ - (address & 0x7FFF) + 0x8000); \ - return 1; \ - \ - /* Read from gamepak ROM, this has to be an immediate load because \ - it might not actually be in memory anymore when we get to it. */ \ - case 0x08: \ - u32 imm = read_memory_constant_##type(address); \ - generate_load_imm(arm_to_mips_reg[rd], imm); \ - return 1; \ - \ - default: \ - return 0; \ - } \ - } \ - #define generate_block_extra_vars() \ u32 stored_pc = pc; \ u8 *update_trampoline \ @@ -1060,12 +1023,6 @@ u32 generate_load_rm_sh_##flags_op(u32 rm) \ generate_load_rm_sh_builder(flags); \ generate_load_rm_sh_builder(no_flags); \ \ -/* generate_known_address_load_builder(u8); \ - generate_known_address_load_builder(u16); \ - generate_known_address_load_builder(u32); \ - generate_known_address_load_builder(s8); \ - generate_known_address_load_builder(s16); */ \ - \ u32 generate_load_offset_sh(u32 rm) \ { \ switch((opcode >> 5) & 0x03) \ @@ -2787,12 +2744,13 @@ static void emit_pmemld_stub( mips_emit_lui(reg_rv, ((base_addr + 0x8000) >> 16)); if (region == 2) { - // EWRAM is a bit special + // Can't do EWRAM with an `andi` instruction (18 bits mask) + mips_emit_ext(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) + } // Need to insert a zero in the addr (due to how it's mapped) - mips_emit_andi(reg_temp, reg_a0, memmask); // Clears all but 15 bits (LSB) - mips_emit_ext(reg_a0, reg_a0, 15, 3); // Gets the 3 higher bits (from the 18) - mips_emit_ins(reg_temp, reg_a0, 16, 3); // Puts the 3 bits into bits 18..16 - mips_emit_addu(reg_rv, reg_rv, reg_temp); // Adds to the base addr + 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 @@ -2862,12 +2820,13 @@ static void emit_pmemst_stub( } if (region == 2) { - // EWRAM is a bit special + // Can't do EWRAM with an `andi` instruction (18 bits mask) + mips_emit_ext(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) + } // Need to insert a zero in the addr (due to how it's mapped) - mips_emit_andi(reg_temp, reg_a0, memmask); // Clears all but 15 bits (LSB) - mips_emit_ext(reg_a0, reg_a0, 15, 3); // Gets the 3 higher bits (from the 18) - mips_emit_ins(reg_temp, reg_a0, 16, 3); // Puts the 3 bits into bits 18..16 - mips_emit_addu(reg_rv, reg_rv, reg_temp); // Adds to the base addr + 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 @@ -2888,7 +2847,12 @@ static void emit_pmemst_stub( // Generate SMC write and tracking // TODO: Should we have SMC checks here also for aligned? if (meminfo->check_smc && !aligned) { - mips_emit_addiu(reg_temp, reg_rv, 0x8000); // -32KB is the addr of the SMC buffer + if (region == 2) { + mips_emit_lui(reg_temp, 0x40000 >> 16); + mips_emit_addu(reg_temp, reg_rv, reg_temp); // SMC lives after the ewram + } else { + mips_emit_addiu(reg_temp, reg_rv, 0x8000); // -32KB is the addr of the SMC buffer + } if (realsize == 2) { mips_emit_lw(reg_temp, reg_temp, base_addr); } else if (realsize == 1) { @@ -3272,8 +3236,8 @@ void init_emitter() { const t_stub_meminfo ldinfo [] = { { emit_pmemld_stub, 0, 0x4000, false, false, (u32)bios_rom }, // 1 Open load / Ignore store - { emit_pmemld_stub, 2, 0x8000, true, false, (u32)&ewram[0x8000] }, - { emit_pmemld_stub, 3, 0x8000, true, false, (u32)&iwram[0x8000] }, // memsize wrong on purpose, see above + { emit_pmemld_stub, 2, 0x8000, true, false, (u32)ewram }, // memsize wrong on purpose + { emit_pmemld_stub, 3, 0x8000, true, false, (u32)&iwram[0x8000] }, { emit_pmemld_stub, 4, 0x400, false, false, (u32)io_registers }, { emit_pmemld_stub, 5, 0x400, false, true, (u32)palette_ram }, { emit_pmemld_stub, 6, 0x0, false, true, (u32)vram }, // same, vram is a special case @@ -3308,8 +3272,8 @@ void init_emitter() { } const t_stub_meminfo stinfo [] = { - { emit_pmemst_stub, 2, 0x8000, true, false, (u32)&ewram[0x8000] }, - { emit_pmemst_stub, 3, 0x8000, true, false, (u32)&iwram[0x8000] }, // memsize wrong on purpose, see above + { emit_pmemst_stub, 2, 0x8000, true, false, (u32)ewram }, + { emit_pmemst_stub, 3, 0x8000, true, false, (u32)&iwram[0x8000] }, // I/O is special and mapped with a function call { emit_palette_hdl, 5, 0x400, false, true, (u32)palette_ram }, { emit_pmemst_stub, 6, 0x0, false, true, (u32)vram }, // same, vram is a special case diff --git a/psp/mips_stub.S b/psp/mips_stub.S index 2d40bf8..5e5a479 100644 --- a/psp/mips_stub.S +++ b/psp/mips_stub.S @@ -44,7 +44,6 @@ .global write_io_epilogue .global memory_map_read -.global memory_map_write .global tmemld .global tmemst .global tmemst @@ -609,9 +608,6 @@ execute_arm_translate_internal: .data .align 6 -memory_map_write: - .space 0x8000 - memory_map_read: .space 0x8000 diff --git a/x86/x86_emit.h b/x86/x86_emit.h index 67a3dc2..68930e1 100644 --- a/x86/x86_emit.h +++ b/x86/x86_emit.h @@ -1485,23 +1485,13 @@ u32 function_cc execute_aligned_load32(u32 address) return read_memory32(address); } -void function_cc execute_aligned_store32(u32 address, u32 source) -{ - u8 *map; - - if(!(address & 0xF0000000) && (map = memory_map_write[address >> 15])) - address32(map, address & 0x7FFF) = source; - else - write_memory32(address, source); -} - #define arm_block_memory_load() \ generate_function_call(execute_aligned_load32); \ generate_store_reg(rv, i) \ #define arm_block_memory_store() \ generate_load_reg_pc(a1, i, 8); \ - generate_function_call(execute_aligned_store32) \ + generate_function_call(write_memory32) \ #define arm_block_memory_final_load() \ arm_block_memory_load() \ @@ -1956,7 +1946,7 @@ u32 function_cc execute_ror_imm_op(u32 value, u32 shift) #define thumb_block_memory_extra_push_lr(base_reg) \ generate_add_reg_reg_imm(a0, s0, (bit_count[reg_list] * 4)); \ generate_load_reg(a1, REG_LR); \ - generate_function_call(execute_aligned_store32) \ + generate_function_call(write_memory32) \ #define thumb_block_memory_load() \ generate_function_call(execute_aligned_load32); \ @@ -1964,7 +1954,7 @@ u32 function_cc execute_ror_imm_op(u32 value, u32 shift) #define thumb_block_memory_store() \ generate_load_reg(a1, i); \ - generate_function_call(execute_aligned_store32) \ + generate_function_call(write_memory32) \ #define thumb_block_memory_final_load() \ thumb_block_memory_load() \ diff --git a/x86/x86_stub.S b/x86/x86_stub.S index 1e338a4..595a789 100644 --- a/x86/x86_stub.S +++ b/x86/x86_stub.S @@ -29,7 +29,6 @@ #define _execute_store_cpsr execute_store_cpsr #define _execute_arm_translate execute_arm_translate #define _memory_map_read memory_map_read -#define _memory_map_write memory_map_write #define _reg reg #define _reg_mode reg_mode #define _oam_update oam_update @@ -68,7 +67,6 @@ .global _execute_arm_translate .global _memory_map_read -.global _memory_map_write .global _reg .global _reg_mode .global _spsr @@ -231,6 +229,20 @@ ext_store_eeprom: # 8bit ext memory routines +ext_store_iwram8: + and $0x7FFF, %eax # wrap around address + mov %dl, (_iwram+0x8000)(%eax) # perform store + cmpb $0, _iwram(%eax) # Check SMC mirror + jne smc_write + ret + +ext_store_ewram8: + and $0x3FFFF, %eax # wrap around address + mov %dl, _ewram(%eax) # perform store + cmpb $0, (_ewram+0x40000)(%eax) # Check SMC mirror + jne smc_write + ret + ext_store_io8: and $0x3FF, %eax # wrap around address and $0xFF, %edx @@ -267,8 +279,8 @@ ext_store_backup: ext_store_u8_jtable: .long ext_store_ignore # 0x00 BIOS, ignore .long ext_store_ignore # 0x01 invalid, ignore - .long ext_store_ignore # 0x02 EWRAM, should have been hit already - .long ext_store_ignore # 0x03 IWRAM, should have been hit already + .long ext_store_ewram8 # 0x02 EWRAM + .long ext_store_iwram8 # 0x03 IWRAM .long ext_store_io8 # 0x04 I/O registers .long ext_store_palette8 # 0x05 Palette RAM .long ext_store_vram8 # 0x06 VRAM @@ -281,7 +293,12 @@ ext_store_u8_jtable: .long ext_store_eeprom # 0x0D EEPROM (possibly) .long ext_store_backup # 0x0E Flash ROM/SRAM -ext_store_u8: +# eax: address to write to +# edx: value to write +# ecx: current pc + +_execute_store_u8: + mov %ecx, REG_PC(%ebx) # write out the PC mov %eax, %ecx # ecx = address shr $24, %ecx # ecx = address >> 24 cmp $15, %ecx @@ -290,47 +307,22 @@ ext_store_u8: mov ext_store_u8_jtable(, %ecx, 4), %ecx jmp *%ecx # jump to table index -# eax: address to write to -# edx: value to write -# ecx: current pc - -_execute_store_u8: - mov %ecx, REG_PC(%ebx) # write out the PC - mov %eax, %ecx # ecx = address - test $0xF0000000, %ecx # check address range - jnz ext_store_u8 # if above perform an extended write - shr $15, %ecx # ecx = page number of address - # load the corresponding memory map offset - mov _memory_map_write(, %ecx, 4), %ecx - test %ecx, %ecx # see if it's NULL - jz ext_store_u8 # if so perform an extended write - and $0x7FFF, %eax # isolate the lower 15bits of the address - mov %dl, (%eax, %ecx) # store the value - # check for self-modifying code - testb $0xFF, -32768(%eax, %ecx) - jne smc_write - ret # return - -_execute_store_u16: - mov %ecx, REG_PC(%ebx) # write out the PC - and $~0x01, %eax # fix alignment - mov %eax, %ecx # ecx = address - test $0xF0000000, %ecx # check address range - jnz ext_store_u16 # if above perform an extended write - shr $15, %ecx # ecx = page number of address - # load the corresponding memory map offset - mov _memory_map_write(, %ecx, 4), %ecx - test %ecx, %ecx # see if it's NULL - jz ext_store_u16 # if so perform an extended write - and $0x7FFF, %eax # isolate the lower 15bits of the address - mov %dx, (%eax, %ecx) # store the value - # check for self-modifying code - testw $0xFFFF, -32768(%eax, %ecx) - jne smc_write - ret # return - # 16bit ext memory routines +ext_store_iwram16: + and $0x7FFF, %eax # wrap around address + mov %dx, (_iwram+0x8000)(%eax) # perform store + cmpw $0, _iwram(%eax) # Check SMC mirror + jne smc_write + ret + +ext_store_ewram16: + and $0x3FFFF, %eax # wrap around address + mov %dx, _ewram(%eax) # perform store + cmpw $0, (_ewram+0x40000)(%eax) # Check SMC mirror + jne smc_write + ret + ext_store_io16: and $0x3FF, %eax # wrap around address and $0xFFFF, %edx @@ -377,8 +369,8 @@ ext_store_rtc: ext_store_u16_jtable: .long ext_store_ignore # 0x00 BIOS, ignore .long ext_store_ignore # 0x01 invalid, ignore - .long ext_store_ignore # 0x02 EWRAM, should have been hit already - .long ext_store_ignore # 0x03 IWRAM, should have been hit already + .long ext_store_ewram16 # 0x02 EWRAM + .long ext_store_iwram16 # 0x03 IWRAM .long ext_store_io16 # 0x04 I/O registers .long ext_store_palette16 # 0x05 Palette RAM .long ext_store_vram16 # 0x06 VRAM @@ -391,7 +383,9 @@ ext_store_u16_jtable: .long ext_store_eeprom # 0x0D EEPROM (possibly) .long ext_store_ignore # 0x0E Flash ROM/SRAM must be 8bit -ext_store_u16: +_execute_store_u16: + mov %ecx, REG_PC(%ebx) # write out the PC + and $~0x01, %eax # fix alignment mov %eax, %ecx # ecx = address shr $24, %ecx # ecx = address >> 24 cmp $15, %ecx @@ -400,26 +394,22 @@ ext_store_u16: mov ext_store_u16_jtable(, %ecx, 4), %ecx jmp *%ecx # jump to table index -_execute_store_u32: - mov %ecx, REG_PC(%ebx) # write out the PC - and $~0x03, %eax # fix alignment - mov %eax, %ecx # ecx = address - test $0xF0000000, %ecx # check address range - jnz ext_store_u32 # if above perform an extended write - shr $15, %ecx # ecx = page number of address - # load the corresponding memory map offset - mov _memory_map_write(, %ecx, 4), %ecx - test %ecx, %ecx # see if it's NULL - jz ext_store_u32 # if so perform an extended write - and $0x7FFF, %eax # isolate the lower 15bits of the address - mov %edx, (%eax, %ecx) # store the value - # check for self-modifying code - testl $0xFFFFFFFF, -32768(%eax, %ecx) - jne smc_write - ret # return it - # 32bit ext memory routines +ext_store_iwram32: + and $0x7FFF, %eax # wrap around address + mov %edx, (_iwram+0x8000)(%eax) # perform store + cmpl $0, _iwram(%eax) # Check SMC mirror + jne smc_write + ret + +ext_store_ewram32: + and $0x3FFFF, %eax # wrap around address + mov %edx, _ewram(%eax) # perform store + cmpl $0, (_ewram+0x40000)(%eax) # Check SMC mirror + jne smc_write + ret + ext_store_io32: and $0x3FF, %eax # wrap around address call _write_io_register32 # perform 32bit I/O register write @@ -451,8 +441,8 @@ ext_store_oam32: ext_store_u32_jtable: .long ext_store_ignore # 0x00 BIOS, ignore .long ext_store_ignore # 0x01 invalid, ignore - .long ext_store_ignore # 0x02 EWRAM, should have been hit already - .long ext_store_ignore # 0x03 IWRAM, should have been hit already + .long ext_store_ewram32 # 0x02 EWRAM + .long ext_store_iwram32 # 0x03 IWRAM .long ext_store_io32 # 0x04 I/O registers .long ext_store_palette32 # 0x05 Palette RAM .long ext_store_vram32 # 0x06 VRAM @@ -466,7 +456,9 @@ ext_store_u32_jtable: .long ext_store_ignore # 0x0E Flash ROM/SRAM must be 8bit -ext_store_u32: +_execute_store_u32: + mov %ecx, REG_PC(%ebx) # write out the PC + and $~0x03, %eax # fix alignment mov %eax, %ecx # ecx = address shr $24, %ecx # ecx = address >> 24 cmp $15, %ecx @@ -507,8 +499,8 @@ smc_write: call _flush_translation_cache_ram lookup_pc: - add $4, %esp - movl $0, CHANGED_PC_STATUS(%ebx) + add $4, %esp # Can't return, discard addr + movl $0, CHANGED_PC_STATUS(%ebx) # Lookup new block and jump to it mov REG_PC(%ebx), %eax testl $0x20, REG_CPSR(%ebx) jz lookup_pc_arm @@ -577,7 +569,5 @@ _reg_mode: _memory_map_read: .space 0x8000 -_memory_map_write: - .space 0x8000