Demacro-ize block_builder_arm/block_builder_thumb

This commit is contained in:
twinaphex 2014-12-10 01:25:37 +01:00
parent fe19474dca
commit 1a8b77c185
1 changed files with 434 additions and 220 deletions

View File

@ -3182,227 +3182,441 @@ block_exit_type block_exits[MAX_EXITS];
#define thumb_fix_pc() \ #define thumb_fix_pc() \
pc &= ~0x01 \ pc &= ~0x01 \
#define translate_block_builder(type) \ s32 translate_block_arm(u32 pc, translation_region_type
s32 translate_block_##type(u32 pc, translation_region_type \ translation_region, u32 smc_enable)
translation_region, u32 smc_enable) \ {
{ \ u32 opcode = 0;
u32 opcode = 0; \ u32 last_opcode;
u32 last_opcode; \ u32 condition;
u32 condition; \ u32 last_condition;
u32 last_condition; \ u32 pc_region = (pc >> 15);
u32 pc_region = (pc >> 15); \ u32 new_pc_region;
u32 new_pc_region; \ u8 *pc_address_block = memory_map_read[pc_region];
u8 *pc_address_block = memory_map_read[pc_region]; \ u32 block_start_pc = pc;
u32 block_start_pc = pc; \ u32 block_end_pc = pc;
u32 block_end_pc = pc; \ u32 block_exit_position = 0;
u32 block_exit_position = 0; \ s32 block_data_position = 0;
s32 block_data_position = 0; \ u32 external_block_exit_position = 0;
u32 external_block_exit_position = 0; \ u32 branch_target;
u32 branch_target; \ u32 cycle_count = 0;
u32 cycle_count = 0; \ u8 *translation_target;
u8 *translation_target; \ u8 *backpatch_address = NULL;
u8 *backpatch_address = NULL; \ u8 *translation_ptr = NULL;
u8 *translation_ptr = NULL; \ u8 *translation_cache_limit = NULL;
u8 *translation_cache_limit = NULL; \ s32 i;
s32 i; \ u32 flag_status;
u32 flag_status; \ block_exit_type external_block_exits[MAX_EXITS];
block_exit_type external_block_exits[MAX_EXITS]; \ generate_block_extra_vars_arm();
generate_block_extra_vars_##type(); \ arm_fix_pc();
type##_fix_pc(); \
\ if(pc_address_block == NULL)
if(pc_address_block == NULL) \ pc_address_block = load_gamepak_page(pc_region & 0x3FF);
pc_address_block = load_gamepak_page(pc_region & 0x3FF); \
\ switch(translation_region)
switch(translation_region) \ {
{ \ case TRANSLATION_REGION_RAM:
case TRANSLATION_REGION_RAM: \ if(pc >= 0x3000000)
if(pc >= 0x3000000) \ {
{ \ if((pc < iwram_code_min) || (iwram_code_min == 0xFFFFFFFF))
if((pc < iwram_code_min) || (iwram_code_min == 0xFFFFFFFF)) \ iwram_code_min = pc;
iwram_code_min = pc; \ }
} \ else
else \
\ if(pc >= 0x2000000)
if(pc >= 0x2000000) \ {
{ \ if((pc < ewram_code_min) || (ewram_code_min == 0xFFFFFFFF))
if((pc < ewram_code_min) || (ewram_code_min == 0xFFFFFFFF)) \ ewram_code_min = pc;
ewram_code_min = pc; \ }
} \
\ translation_ptr = ram_translation_ptr;
translation_ptr = ram_translation_ptr; \ translation_cache_limit =
translation_cache_limit = \ ram_translation_cache + RAM_TRANSLATION_CACHE_SIZE -
ram_translation_cache + RAM_TRANSLATION_CACHE_SIZE - \ TRANSLATION_CACHE_LIMIT_THRESHOLD;
TRANSLATION_CACHE_LIMIT_THRESHOLD; \ break;
break; \
\ case TRANSLATION_REGION_ROM:
case TRANSLATION_REGION_ROM: \ translation_ptr = rom_translation_ptr;
translation_ptr = rom_translation_ptr; \ translation_cache_limit =
translation_cache_limit = \ rom_translation_cache + ROM_TRANSLATION_CACHE_SIZE -
rom_translation_cache + ROM_TRANSLATION_CACHE_SIZE - \ TRANSLATION_CACHE_LIMIT_THRESHOLD;
TRANSLATION_CACHE_LIMIT_THRESHOLD; \ break;
break; \
\ case TRANSLATION_REGION_BIOS:
case TRANSLATION_REGION_BIOS: \ translation_ptr = bios_translation_ptr;
translation_ptr = bios_translation_ptr; \ translation_cache_limit = bios_translation_cache +
translation_cache_limit = bios_translation_cache + \ BIOS_TRANSLATION_CACHE_SIZE;
BIOS_TRANSLATION_CACHE_SIZE; \ break;
break; \ }
} \
\ generate_block_prologue();
generate_block_prologue(); \
\ /* This is a function because it's used a lot more than it might seem (all
/* 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
of the data processing functions can access it), and its expansion was \ massacreing the compiler. */
massacreing the compiler. */ \
\ if(smc_enable)
if(smc_enable) \ {
{ \ scan_block(arm, yes);
scan_block(type, yes); \ }
} \ else
else \ {
{ \ scan_block(arm, no);
scan_block(type, no); \ }
} \
\ for(i = 0; i < block_exit_position; i++)
for(i = 0; i < block_exit_position; i++) \ {
{ \ branch_target = block_exits[i].branch_target;
branch_target = block_exits[i].branch_target; \
\ if((branch_target > block_start_pc) &&
if((branch_target > block_start_pc) && \ (branch_target < block_end_pc))
(branch_target < block_end_pc)) \ {
{ \ block_data[(branch_target - block_start_pc) /
block_data[(branch_target - block_start_pc) / \ arm_instruction_width].update_cycles = 1;
type##_instruction_width].update_cycles = 1; \ }
} \ }
} \
\ arm_dead_flag_eliminate();
type##_dead_flag_eliminate(); \
\ block_exit_position = 0;
block_exit_position = 0; \ block_data_position = 0;
block_data_position = 0; \
\ last_condition = 0x0E;
last_condition = 0x0E; \
\ while(pc != block_end_pc)
while(pc != block_end_pc) \ {
{ \ block_data[block_data_position].block_offset = translation_ptr;
block_data[block_data_position].block_offset = translation_ptr; \ arm_base_cycles();
type##_base_cycles(); \ /*generate_step_debug();*/
/*generate_step_debug();*/ \
\ translate_arm_instruction();
translate_##type##_instruction(); \ block_data_position++;
block_data_position++; \
\ /* If it went too far the cache needs to be flushed and the process
/* If it went too far the cache needs to be flushed and the process \ restarted. Because we might already be nested several stages in
restarted. Because we might already be nested several stages in \ a simple recursive call here won't work, it has to pedal out to
a simple recursive call here won't work, it has to pedal out to \ the beginning. */
the beginning. */ \
\ if(translation_ptr > translation_cache_limit)
if(translation_ptr > translation_cache_limit) \ {
{ \ translation_flush_count++;
translation_flush_count++; \
\ switch(translation_region)
switch(translation_region) \ {
{ \ case TRANSLATION_REGION_RAM:
case TRANSLATION_REGION_RAM: \ flush_translation_cache_ram();
flush_translation_cache_ram(); \ break;
break; \
\ case TRANSLATION_REGION_ROM:
case TRANSLATION_REGION_ROM: \ flush_translation_cache_rom();
flush_translation_cache_rom(); \ break;
break; \
\ case TRANSLATION_REGION_BIOS:
case TRANSLATION_REGION_BIOS: \ flush_translation_cache_bios();
flush_translation_cache_bios(); \ break;
break; \ }
} \
\ return -1;
return -1; \ }
} \
\ /* If the next instruction is a block entry point update the
/* If the next instruction is a block entry point update the \ cycle counter and update */
cycle counter and update */ \ if(block_data[block_data_position].update_cycles == 1)
if(block_data[block_data_position].update_cycles == 1) \ {
{ \ generate_cycle_update();
generate_cycle_update(); \ }
} \ }
} \ for(i = 0; i < translation_gate_targets; i++)
for(i = 0; i < translation_gate_targets; i++) \ {
{ \ if(pc == translation_gate_target_pc[i])
if(pc == translation_gate_target_pc[i]) \ {
{ \ generate_translation_gate(arm);
generate_translation_gate(type); \ break;
break; \ }
} \ }
} \
\ for(i = 0; i < block_exit_position; i++)
for(i = 0; i < block_exit_position; i++) \ {
{ \ branch_target = block_exits[i].branch_target;
branch_target = block_exits[i].branch_target; \
\ if((branch_target >= block_start_pc) && (branch_target < block_end_pc))
if((branch_target >= block_start_pc) && (branch_target < block_end_pc)) \ {
{ \ /* Internal branch, patch to recorded address */
/* Internal branch, patch to recorded address */ \ translation_target =
translation_target = \ block_data[(branch_target - block_start_pc) /
block_data[(branch_target - block_start_pc) / \ arm_instruction_width].block_offset;
type##_instruction_width].block_offset; \
\ generate_branch_patch_unconditional(block_exits[i].branch_source,
generate_branch_patch_unconditional(block_exits[i].branch_source, \ translation_target);
translation_target); \ }
} \ else
else \ {
{ \ /* External branch, save for later */
/* External branch, save for later */ \ external_block_exits[external_block_exit_position].branch_target =
external_block_exits[external_block_exit_position].branch_target = \ branch_target;
branch_target; \ external_block_exits[external_block_exit_position].branch_source =
external_block_exits[external_block_exit_position].branch_source = \ block_exits[i].branch_source;
block_exits[i].branch_source; \ external_block_exit_position++;
external_block_exit_position++; \ }
} \ }
} \
\ switch(translation_region)
switch(translation_region) \ {
{ \ case TRANSLATION_REGION_RAM:
case TRANSLATION_REGION_RAM: \ if(pc >= 0x3000000)
if(pc >= 0x3000000) \ {
{ \ if((pc > iwram_code_max) || (iwram_code_max == 0xFFFFFFFF))
if((pc > iwram_code_max) || (iwram_code_max == 0xFFFFFFFF)) \ iwram_code_max = pc;
iwram_code_max = pc; \ }
} \ else
else \
\ if(pc >= 0x2000000)
if(pc >= 0x2000000) \ {
{ \ if((pc > ewram_code_max) || (ewram_code_max == 0xFFFFFFFF))
if((pc > ewram_code_max) || (ewram_code_max == 0xFFFFFFFF)) \ ewram_code_max = pc;
ewram_code_max = pc; \ }
} \
\ ram_translation_ptr = translation_ptr;
ram_translation_ptr = translation_ptr; \ break;
break; \
\ case TRANSLATION_REGION_ROM:
case TRANSLATION_REGION_ROM: \ rom_translation_ptr = translation_ptr;
rom_translation_ptr = translation_ptr; \ break;
break; \
\ case TRANSLATION_REGION_BIOS:
case TRANSLATION_REGION_BIOS: \ bios_translation_ptr = translation_ptr;
bios_translation_ptr = translation_ptr; \ break;
break; \ }
} \
\ for(i = 0; i < external_block_exit_position; i++)
for(i = 0; i < external_block_exit_position; i++) \ {
{ \ branch_target = external_block_exits[i].branch_target;
branch_target = external_block_exits[i].branch_target; \ arm_link_block();
type##_link_block(); \ if(translation_target == NULL)
if(translation_target == NULL) \ return -1;
return -1; \ generate_branch_patch_unconditional(
generate_branch_patch_unconditional( \ external_block_exits[i].branch_source, translation_target);
external_block_exits[i].branch_source, translation_target); \ }
} \
\ return 0;
return 0; \ }
} \
translate_block_builder(arm); s32 translate_block_thumb(u32 pc, translation_region_type
translate_block_builder(thumb); 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() void flush_translation_cache_ram()
{ {