From 1a8b77c1850db3fb4545c55adb07dbf1e7584dbf Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 10 Dec 2014 01:25:37 +0100 Subject: [PATCH] Demacro-ize block_builder_arm/block_builder_thumb --- cpu_threaded.c | 654 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 434 insertions(+), 220 deletions(-) diff --git a/cpu_threaded.c b/cpu_threaded.c index 0c4e924..30abec3 100644 --- a/cpu_threaded.c +++ b/cpu_threaded.c @@ -3182,227 +3182,441 @@ block_exit_type block_exits[MAX_EXITS]; #define thumb_fix_pc() \ pc &= ~0x01 \ -#define translate_block_builder(type) \ -s32 translate_block_##type(u32 pc, translation_region_type \ - translation_region, u32 smc_enable) \ -{ \ - 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]; \ - u32 block_start_pc = pc; \ - u32 block_end_pc = pc; \ - u32 block_exit_position = 0; \ - s32 block_data_position = 0; \ - u32 external_block_exit_position = 0; \ - u32 branch_target; \ - u32 cycle_count = 0; \ - u8 *translation_target; \ - u8 *backpatch_address = NULL; \ - u8 *translation_ptr = NULL; \ - u8 *translation_cache_limit = NULL; \ - s32 i; \ - u32 flag_status; \ - block_exit_type external_block_exits[MAX_EXITS]; \ - generate_block_extra_vars_##type(); \ - type##_fix_pc(); \ - \ - if(pc_address_block == NULL) \ - pc_address_block = load_gamepak_page(pc_region & 0x3FF); \ - \ - switch(translation_region) \ - { \ - case TRANSLATION_REGION_RAM: \ - if(pc >= 0x3000000) \ - { \ - if((pc < iwram_code_min) || (iwram_code_min == 0xFFFFFFFF)) \ - iwram_code_min = pc; \ - } \ - else \ - \ - if(pc >= 0x2000000) \ - { \ - if((pc < ewram_code_min) || (ewram_code_min == 0xFFFFFFFF)) \ - ewram_code_min = pc; \ - } \ - \ - translation_ptr = ram_translation_ptr; \ - translation_cache_limit = \ - ram_translation_cache + RAM_TRANSLATION_CACHE_SIZE - \ - TRANSLATION_CACHE_LIMIT_THRESHOLD; \ - break; \ - \ - case TRANSLATION_REGION_ROM: \ - translation_ptr = rom_translation_ptr; \ - translation_cache_limit = \ - rom_translation_cache + ROM_TRANSLATION_CACHE_SIZE - \ - TRANSLATION_CACHE_LIMIT_THRESHOLD; \ - break; \ - \ - case TRANSLATION_REGION_BIOS: \ - translation_ptr = bios_translation_ptr; \ - translation_cache_limit = bios_translation_cache + \ - BIOS_TRANSLATION_CACHE_SIZE; \ - break; \ - } \ - \ - generate_block_prologue(); \ - \ - /* This is a function because it's used a lot more than it might seem (all \ - of the data processing functions can access it), and its expansion was \ - massacreing the compiler. */ \ - \ - if(smc_enable) \ - { \ - scan_block(type, yes); \ - } \ - else \ - { \ - scan_block(type, no); \ - } \ - \ - for(i = 0; i < block_exit_position; i++) \ - { \ - branch_target = block_exits[i].branch_target; \ - \ - if((branch_target > block_start_pc) && \ - (branch_target < block_end_pc)) \ - { \ - block_data[(branch_target - block_start_pc) / \ - type##_instruction_width].update_cycles = 1; \ - } \ - } \ - \ - type##_dead_flag_eliminate(); \ - \ - 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; \ - type##_base_cycles(); \ - /*generate_step_debug();*/ \ - \ - translate_##type##_instruction(); \ - block_data_position++; \ - \ - /* If it went too far the cache needs to be flushed and the process \ - restarted. Because we might already be nested several stages in \ - a simple recursive call here won't work, it has to pedal out to \ - the beginning. */ \ - \ - if(translation_ptr > translation_cache_limit) \ - { \ - translation_flush_count++; \ - \ - switch(translation_region) \ - { \ - case TRANSLATION_REGION_RAM: \ - flush_translation_cache_ram(); \ - break; \ - \ - case TRANSLATION_REGION_ROM: \ - flush_translation_cache_rom(); \ - break; \ - \ - case TRANSLATION_REGION_BIOS: \ - flush_translation_cache_bios(); \ - break; \ - } \ - \ - return -1; \ - } \ - \ - /* If the next instruction is a block entry point update the \ - cycle counter and update */ \ - if(block_data[block_data_position].update_cycles == 1) \ - { \ - generate_cycle_update(); \ - } \ - } \ - for(i = 0; i < translation_gate_targets; i++) \ - { \ - if(pc == translation_gate_target_pc[i]) \ - { \ - generate_translation_gate(type); \ - break; \ - } \ - } \ - \ - for(i = 0; i < block_exit_position; i++) \ - { \ - branch_target = block_exits[i].branch_target; \ - \ - if((branch_target >= block_start_pc) && (branch_target < block_end_pc)) \ - { \ - /* Internal branch, patch to recorded address */ \ - translation_target = \ - block_data[(branch_target - block_start_pc) / \ - type##_instruction_width].block_offset; \ - \ - generate_branch_patch_unconditional(block_exits[i].branch_source, \ - translation_target); \ - } \ - else \ - { \ - /* External branch, save for later */ \ - external_block_exits[external_block_exit_position].branch_target = \ - branch_target; \ - external_block_exits[external_block_exit_position].branch_source = \ - block_exits[i].branch_source; \ - external_block_exit_position++; \ - } \ - } \ - \ - switch(translation_region) \ - { \ - case TRANSLATION_REGION_RAM: \ - if(pc >= 0x3000000) \ - { \ - if((pc > iwram_code_max) || (iwram_code_max == 0xFFFFFFFF)) \ - iwram_code_max = pc; \ - } \ - else \ - \ - if(pc >= 0x2000000) \ - { \ - if((pc > ewram_code_max) || (ewram_code_max == 0xFFFFFFFF)) \ - ewram_code_max = pc; \ - } \ - \ - ram_translation_ptr = translation_ptr; \ - break; \ - \ - case TRANSLATION_REGION_ROM: \ - rom_translation_ptr = translation_ptr; \ - break; \ - \ - case TRANSLATION_REGION_BIOS: \ - bios_translation_ptr = translation_ptr; \ - break; \ - } \ - \ - for(i = 0; i < external_block_exit_position; i++) \ - { \ - branch_target = external_block_exits[i].branch_target; \ - type##_link_block(); \ - if(translation_target == NULL) \ - return -1; \ - generate_branch_patch_unconditional( \ - external_block_exits[i].branch_source, translation_target); \ - } \ - \ - return 0; \ -} \ +s32 translate_block_arm(u32 pc, translation_region_type + translation_region, u32 smc_enable) +{ + 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]; + u32 block_start_pc = pc; + u32 block_end_pc = pc; + u32 block_exit_position = 0; + s32 block_data_position = 0; + u32 external_block_exit_position = 0; + u32 branch_target; + u32 cycle_count = 0; + u8 *translation_target; + u8 *backpatch_address = NULL; + u8 *translation_ptr = NULL; + u8 *translation_cache_limit = NULL; + s32 i; + u32 flag_status; + block_exit_type external_block_exits[MAX_EXITS]; + generate_block_extra_vars_arm(); + arm_fix_pc(); + + if(pc_address_block == NULL) + pc_address_block = load_gamepak_page(pc_region & 0x3FF); + + switch(translation_region) + { + case TRANSLATION_REGION_RAM: + if(pc >= 0x3000000) + { + if((pc < iwram_code_min) || (iwram_code_min == 0xFFFFFFFF)) + iwram_code_min = pc; + } + else + + if(pc >= 0x2000000) + { + if((pc < ewram_code_min) || (ewram_code_min == 0xFFFFFFFF)) + ewram_code_min = pc; + } + + translation_ptr = ram_translation_ptr; + translation_cache_limit = + ram_translation_cache + RAM_TRANSLATION_CACHE_SIZE - + TRANSLATION_CACHE_LIMIT_THRESHOLD; + break; + + case TRANSLATION_REGION_ROM: + translation_ptr = rom_translation_ptr; + translation_cache_limit = + rom_translation_cache + ROM_TRANSLATION_CACHE_SIZE - + TRANSLATION_CACHE_LIMIT_THRESHOLD; + break; + + case TRANSLATION_REGION_BIOS: + translation_ptr = bios_translation_ptr; + translation_cache_limit = bios_translation_cache + + BIOS_TRANSLATION_CACHE_SIZE; + break; + } + + generate_block_prologue(); + + /* This is a function because it's used a lot more than it might seem (all + of the data processing functions can access it), and its expansion was + massacreing the compiler. */ + + if(smc_enable) + { + scan_block(arm, yes); + } + else + { + scan_block(arm, no); + } + + for(i = 0; i < block_exit_position; i++) + { + branch_target = block_exits[i].branch_target; + + if((branch_target > block_start_pc) && + (branch_target < block_end_pc)) + { + block_data[(branch_target - block_start_pc) / + arm_instruction_width].update_cycles = 1; + } + } + + arm_dead_flag_eliminate(); + + 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; + arm_base_cycles(); + /*generate_step_debug();*/ + + translate_arm_instruction(); + block_data_position++; + + /* If it went too far the cache needs to be flushed and the process + restarted. Because we might already be nested several stages in + a simple recursive call here won't work, it has to pedal out to + the beginning. */ + + if(translation_ptr > translation_cache_limit) + { + translation_flush_count++; + + switch(translation_region) + { + case TRANSLATION_REGION_RAM: + flush_translation_cache_ram(); + break; + + case TRANSLATION_REGION_ROM: + flush_translation_cache_rom(); + break; + + case TRANSLATION_REGION_BIOS: + flush_translation_cache_bios(); + break; + } + + return -1; + } + + /* If the next instruction is a block entry point update the + cycle counter and update */ + if(block_data[block_data_position].update_cycles == 1) + { + generate_cycle_update(); + } + } + for(i = 0; i < translation_gate_targets; i++) + { + if(pc == translation_gate_target_pc[i]) + { + generate_translation_gate(arm); + break; + } + } + + for(i = 0; i < block_exit_position; i++) + { + branch_target = block_exits[i].branch_target; + + if((branch_target >= block_start_pc) && (branch_target < block_end_pc)) + { + /* Internal branch, patch to recorded address */ + translation_target = + block_data[(branch_target - block_start_pc) / + arm_instruction_width].block_offset; + + generate_branch_patch_unconditional(block_exits[i].branch_source, + translation_target); + } + else + { + /* External branch, save for later */ + external_block_exits[external_block_exit_position].branch_target = + branch_target; + external_block_exits[external_block_exit_position].branch_source = + block_exits[i].branch_source; + external_block_exit_position++; + } + } + + switch(translation_region) + { + case TRANSLATION_REGION_RAM: + if(pc >= 0x3000000) + { + if((pc > iwram_code_max) || (iwram_code_max == 0xFFFFFFFF)) + iwram_code_max = pc; + } + else + + if(pc >= 0x2000000) + { + if((pc > ewram_code_max) || (ewram_code_max == 0xFFFFFFFF)) + ewram_code_max = pc; + } + + ram_translation_ptr = translation_ptr; + break; + + case TRANSLATION_REGION_ROM: + rom_translation_ptr = translation_ptr; + break; + + case TRANSLATION_REGION_BIOS: + bios_translation_ptr = translation_ptr; + break; + } + + for(i = 0; i < external_block_exit_position; i++) + { + branch_target = external_block_exits[i].branch_target; + arm_link_block(); + if(translation_target == NULL) + return -1; + generate_branch_patch_unconditional( + external_block_exits[i].branch_source, translation_target); + } + + return 0; +} -translate_block_builder(arm); -translate_block_builder(thumb); +s32 translate_block_thumb(u32 pc, translation_region_type + translation_region, u32 smc_enable) +{ + 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]; + u32 block_start_pc = pc; + u32 block_end_pc = pc; + u32 block_exit_position = 0; + s32 block_data_position = 0; + u32 external_block_exit_position = 0; + u32 branch_target; + u32 cycle_count = 0; + u8 *translation_target; + u8 *backpatch_address = NULL; + u8 *translation_ptr = NULL; + u8 *translation_cache_limit = NULL; + s32 i; + u32 flag_status; + block_exit_type external_block_exits[MAX_EXITS]; + generate_block_extra_vars_thumb(); + thumb_fix_pc(); + + if(pc_address_block == NULL) + pc_address_block = load_gamepak_page(pc_region & 0x3FF); + + switch(translation_region) + { + case TRANSLATION_REGION_RAM: + if(pc >= 0x3000000) + { + if((pc < iwram_code_min) || (iwram_code_min == 0xFFFFFFFF)) + iwram_code_min = pc; + } + else + + if(pc >= 0x2000000) + { + if((pc < ewram_code_min) || (ewram_code_min == 0xFFFFFFFF)) + ewram_code_min = pc; + } + + translation_ptr = ram_translation_ptr; + translation_cache_limit = + ram_translation_cache + RAM_TRANSLATION_CACHE_SIZE - + TRANSLATION_CACHE_LIMIT_THRESHOLD; + break; + + case TRANSLATION_REGION_ROM: + translation_ptr = rom_translation_ptr; + translation_cache_limit = + rom_translation_cache + ROM_TRANSLATION_CACHE_SIZE - + TRANSLATION_CACHE_LIMIT_THRESHOLD; + break; + + case TRANSLATION_REGION_BIOS: + translation_ptr = bios_translation_ptr; + translation_cache_limit = bios_translation_cache + + BIOS_TRANSLATION_CACHE_SIZE; + break; + } + + generate_block_prologue(); + + /* This is a function because it's used a lot more than it might seem (all + of the data processing functions can access it), and its expansion was + massacreing the compiler. */ + + if(smc_enable) + { + scan_block(thumb, yes); + } + else + { + scan_block(thumb, no); + } + + for(i = 0; i < block_exit_position; i++) + { + branch_target = block_exits[i].branch_target; + + if((branch_target > block_start_pc) && + (branch_target < block_end_pc)) + { + block_data[(branch_target - block_start_pc) / + thumb_instruction_width].update_cycles = 1; + } + } + + thumb_dead_flag_eliminate(); + + 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; + thumb_base_cycles(); + /*generate_step_debug();*/ + + translate_thumb_instruction(); + block_data_position++; + + /* If it went too far the cache needs to be flushed and the process + restarted. Because we might already be nested several stages in + a simple recursive call here won't work, it has to pedal out to + the beginning. */ + + if(translation_ptr > translation_cache_limit) + { + translation_flush_count++; + + switch(translation_region) + { + case TRANSLATION_REGION_RAM: + flush_translation_cache_ram(); + break; + + case TRANSLATION_REGION_ROM: + flush_translation_cache_rom(); + break; + + case TRANSLATION_REGION_BIOS: + flush_translation_cache_bios(); + break; + } + + return -1; + } + + /* If the next instruction is a block entry point update the + cycle counter and update */ + if(block_data[block_data_position].update_cycles == 1) + { + generate_cycle_update(); + } + } + for(i = 0; i < translation_gate_targets; i++) + { + if(pc == translation_gate_target_pc[i]) + { + generate_translation_gate(thumb); + break; + } + } + + for(i = 0; i < block_exit_position; i++) + { + branch_target = block_exits[i].branch_target; + + if((branch_target >= block_start_pc) && (branch_target < block_end_pc)) + { + /* Internal branch, patch to recorded address */ + translation_target = + block_data[(branch_target - block_start_pc) / + thumb_instruction_width].block_offset; + + generate_branch_patch_unconditional(block_exits[i].branch_source, + translation_target); + } + else + { + /* External branch, save for later */ + external_block_exits[external_block_exit_position].branch_target = + branch_target; + external_block_exits[external_block_exit_position].branch_source = + block_exits[i].branch_source; + external_block_exit_position++; + } + } + + switch(translation_region) + { + case TRANSLATION_REGION_RAM: + if(pc >= 0x3000000) + { + if((pc > iwram_code_max) || (iwram_code_max == 0xFFFFFFFF)) + iwram_code_max = pc; + } + else + + if(pc >= 0x2000000) + { + if((pc > ewram_code_max) || (ewram_code_max == 0xFFFFFFFF)) + ewram_code_max = pc; + } + + ram_translation_ptr = translation_ptr; + break; + + case TRANSLATION_REGION_ROM: + rom_translation_ptr = translation_ptr; + break; + + case TRANSLATION_REGION_BIOS: + bios_translation_ptr = translation_ptr; + break; + } + + for(i = 0; i < external_block_exit_position; i++) + { + branch_target = external_block_exits[i].branch_target; + thumb_link_block(); + if(translation_target == NULL) + return -1; + generate_branch_patch_unconditional( + external_block_exits[i].branch_source, translation_target); + } + + return 0; +} void flush_translation_cache_ram() {