[Interp] Simplify PC calculation

This commit is contained in:
David Guillen Fandos 2023-11-03 00:30:35 +01:00
parent 64d0a066b4
commit 875c192257

139
cpu.cc
View file

@ -566,7 +566,7 @@ const u8 bit_count[256] =
(v_flag << 28) | (reg[REG_CPSR] & 0xFF) \ (v_flag << 28) | (reg[REG_CPSR] & 0xFF) \
#define check_pc_region() \ #define check_pc_region() \
new_pc_region = (pc >> 15); \ new_pc_region = (reg[REG_PC] >> 15); \
if(new_pc_region != pc_region) \ if(new_pc_region != pc_region) \
{ \ { \
pc_region = new_pc_region; \ pc_region = new_pc_region; \
@ -578,20 +578,8 @@ const u8 bit_count[256] =
} \ } \
#define arm_update_pc() \
pc = reg[REG_PC] \
#define arm_pc_offset(val) \ #define arm_pc_offset(val) \
pc += val; \ reg[REG_PC] += val \
reg[REG_PC] = pc \
#define arm_pc_offset_update(val) \
pc += val; \
reg[REG_PC] = pc \
#define arm_pc_offset_update_direct(val) \
pc = val; \
reg[REG_PC] = pc \
// It should be okay to still generate result flags, spsr will overwrite them. // It should be okay to still generate result flags, spsr will overwrite them.
@ -606,7 +594,6 @@ const u8 bit_count[256] =
REG_SPSR(MODE_IRQ) = reg[REG_CPSR]; \ REG_SPSR(MODE_IRQ) = reg[REG_CPSR]; \
reg[REG_CPSR] = 0xD2; \ reg[REG_CPSR] = 0xD2; \
reg[REG_PC] = 0x00000018; \ reg[REG_PC] = 0x00000018; \
arm_update_pc(); \
set_cpu_mode(MODE_IRQ); \ set_cpu_mode(MODE_IRQ); \
goto arm_loop; \ goto arm_loop; \
} \ } \
@ -621,7 +608,6 @@ const u8 bit_count[256] =
set_cpu_mode(cpu_modes[reg[REG_CPSR] & 0xF]); \ set_cpu_mode(cpu_modes[reg[REG_CPSR] & 0xF]); \
check_for_interrupts(); \ check_for_interrupts(); \
} \ } \
arm_update_pc(); \
\ \
if(reg[REG_CPSR] & 0x20) \ if(reg[REG_CPSR] & 0x20) \
goto thumb_loop; \ goto thumb_loop; \
@ -651,11 +637,6 @@ const u8 bit_count[256] =
dest = expr; \ dest = expr; \
arm_pc_offset(-4); \ arm_pc_offset(-4); \
reg[rd] = dest; \ reg[rd] = dest; \
\
if(rd == 15) \
{ \
arm_update_pc(); \
} \
} \ } \
#define flags_vars(src_a, src_b) \ #define flags_vars(src_a, src_b) \
@ -854,7 +835,7 @@ const u32 spsr_masks[4] = { 0x00000000, 0x000000EF, 0xF0000000, 0xF00000EF };
} \ } \
\ \
if ( \ if ( \
(((_address >> 24) == 0) && (pc >= 0x4000)) || /* BIOS reading */ \ (((_address >> 24) == 0) && (reg[REG_PC] >= 0x4000)) || /* BIOS read */ \
(_address & aligned_address_mask##size) || /* Unaligned access */ \ (_address & aligned_address_mask##size) || /* Unaligned access */ \
!(map = memory_map_read[_address >> 15]) /* Unmapped memory */ \ !(map = memory_map_read[_address >> 15]) /* Unmapped memory */ \
) \ ) \
@ -953,11 +934,6 @@ const u32 spsr_masks[4] = { 0x00000000, 0x000000EF, 0xF0000000, 0xF00000EF };
if(rd == 15) \ if(rd == 15) \
reg_op += 4 \ reg_op += 4 \
#define arm_access_memory_pc_postadjust_load() \
arm_update_pc() \
#define arm_access_memory_pc_postadjust_store() \
#define load_reg_op reg[rd] \ #define load_reg_op reg[rd] \
#define store_reg_op reg_op \ #define store_reg_op reg_op \
@ -973,7 +949,6 @@ const u32 spsr_masks[4] = { 0x00000000, 0x000000EF, 0xF0000000, 0xF00000EF };
arm_pc_offset(-4); \ arm_pc_offset(-4); \
arm_access_memory_writeback_##wb(wb_off_op); \ arm_access_memory_writeback_##wb(wb_off_op); \
access_type##_memory_##mem_type(address, access_type##_reg_op); \ access_type##_memory_##mem_type(address, access_type##_reg_op); \
arm_access_memory_pc_postadjust_##access_type(); \
} \ } \
#define word_bit_count(word) \ #define word_bit_count(word) \
@ -1020,11 +995,10 @@ const u32 spsr_masks[4] = { 0x00000000, 0x000000EF, 0xF0000000, 0xF00000EF };
#define arm_block_memory_writeback_no() \ #define arm_block_memory_writeback_no() \
#define arm_block_memory_load_pc() \ #define arm_block_memory_load_pc() \
load_aligned32(address, pc); \ load_aligned32(address, reg[REG_PC]); \
reg[REG_PC] = pc \
#define arm_block_memory_store_pc() \ #define arm_block_memory_store_pc() \
store_aligned32(address, pc + 4) \ store_aligned32(address, reg[REG_PC] + 4) \
#define arm_block_memory(access_type, offset_type, writeback_type, s_bit) \ #define arm_block_memory(access_type, offset_type, writeback_type, s_bit) \
{ \ { \
@ -1067,20 +1041,8 @@ const u32 spsr_masks[4] = { 0x00000000, 0x000000EF, 0xF0000000, 0xF00000EF };
goto skip_instruction; \ goto skip_instruction; \
} \ } \
#define thumb_update_pc() \
pc = reg[REG_PC] \
#define thumb_pc_offset(val) \ #define thumb_pc_offset(val) \
pc += val; \ reg[REG_PC] += val \
reg[REG_PC] = pc \
#define thumb_pc_offset_update(val) \
pc += val; \
reg[REG_PC] = pc \
#define thumb_pc_offset_update_direct(val) \
pc = val; \
reg[REG_PC] = pc \
// Types: add_sub, add_sub_imm, alu_op, imm // Types: add_sub, add_sub_imm, alu_op, imm
// Affects N/Z/C/V flags // Affects N/Z/C/V flags
@ -1298,7 +1260,6 @@ const u32 spsr_masks[4] = { 0x00000000, 0x000000EF, 0xF0000000, 0xF00000EF };
if(rd == 15) \ if(rd == 15) \
{ \ { \
reg[REG_PC] = dest & ~0x01; \ reg[REG_PC] = dest & ~0x01; \
thumb_update_pc(); \
} \ } \
else \ else \
{ \ { \
@ -1336,9 +1297,8 @@ const u32 spsr_masks[4] = { 0x00000000, 0x000000EF, 0xF0000000, 0xF00000EF };
address -= offset \ address -= offset \
#define thumb_block_address_postadjust_pop_pc() \ #define thumb_block_address_postadjust_pop_pc() \
load_memory_u32(address + offset, pc); \ load_memory_u32(address + offset, reg[REG_PC]); \
pc &= ~0x01; \ reg[REG_PC] &= ~0x01; \
reg[REG_PC] = pc; \
address += offset + 4 \ address += offset + 4 \
#define thumb_block_address_postadjust_push_lr() \ #define thumb_block_address_postadjust_push_lr() \
@ -1388,7 +1348,7 @@ const u32 spsr_masks[4] = { 0x00000000, 0x000000EF, 0xF0000000, 0xF00000EF };
{ \ { \
thumb_pc_offset(2); \ thumb_pc_offset(2); \
} \ } \
cycles_remaining -= ws_cyc_nseq[pc >> 24][0]; \ cycles_remaining -= ws_cyc_nseq[reg[REG_PC] >> 24][0]; \
} \ } \
// When a mode change occurs from non-FIQ to non-FIQ retire the current // When a mode change occurs from non-FIQ to non-FIQ retire the current
@ -1511,21 +1471,16 @@ u16 io_registers[512];
void execute_arm(u32 cycles) void execute_arm(u32 cycles)
{ {
u32 pc = reg[REG_PC];
u32 opcode; u32 opcode;
u32 condition; u32 condition;
u32 n_flag, z_flag, c_flag, v_flag; u32 n_flag, z_flag, c_flag, v_flag;
u32 pc_region = (pc >> 15); u32 pc_region = (reg[REG_PC] >> 15);
u8 *pc_address_block = memory_map_read[pc_region]; u8 *pc_address_block = memory_map_read[pc_region];
u32 new_pc_region; u32 new_pc_region;
s32 cycles_remaining; s32 cycles_remaining;
u32 update_ret; u32 update_ret;
cpu_alert_type cpu_alert; cpu_alert_type cpu_alert;
u32 old_pc;
(void)old_pc;
if(!pc_address_block) if(!pc_address_block)
pc_address_block = load_gamepak_page(pc_region & 0x3FF); pc_address_block = load_gamepak_page(pc_region & 0x3FF);
touch_gamepak_page(pc_region); touch_gamepak_page(pc_region);
@ -1543,7 +1498,6 @@ void execute_arm(u32 cycles)
} }
cpu_alert = CPU_ALERT_NONE; cpu_alert = CPU_ALERT_NONE;
pc = reg[REG_PC];
extract_flags(); extract_flags();
if(reg[REG_CPSR] & 0x20) if(reg[REG_CPSR] & 0x20)
@ -1556,16 +1510,14 @@ arm_loop:
collapse_flags(); collapse_flags();
/* Process cheats if we are about to execute the cheat hook */ /* Process cheats if we are about to execute the cheat hook */
if (pc == cheat_master_hook) if (reg[REG_PC] == cheat_master_hook)
process_cheats(); process_cheats();
old_pc = pc;
/* Execute ARM instruction */ /* Execute ARM instruction */
using_instruction(arm); using_instruction(arm);
check_pc_region(); check_pc_region();
pc &= ~0x03; reg[REG_PC] &= ~0x03;
opcode = readaddress32(pc_address_block, (pc & 0x7FFF)); opcode = readaddress32(pc_address_block, (reg[REG_PC] & 0x7FFF));
condition = opcode >> 28; condition = opcode >> 28;
switch(condition) switch(condition)
@ -2136,16 +2088,15 @@ arm_loop:
u32 src = reg[rn]; u32 src = reg[rn];
if(src & 0x01) if(src & 0x01)
{ {
src -= 1; reg[REG_PC] = src - 1;
arm_pc_offset_update_direct(src);
reg[REG_CPSR] |= 0x20; reg[REG_CPSR] |= 0x20;
goto thumb_loop; goto thumb_loop;
} }
else else
{ {
arm_pc_offset_update_direct(src); reg[REG_PC] = src;
} }
cycles_remaining -= ws_cyc_nseq[pc >> 24][1]; cycles_remaining -= ws_cyc_nseq[reg[REG_PC] >> 24][1];
} }
else else
{ {
@ -3073,8 +3024,8 @@ arm_loop:
{ {
/* B offset */ /* B offset */
arm_decode_branch(); arm_decode_branch();
arm_pc_offset_update(offset + 8); reg[REG_PC] += offset + 8;
cycles_remaining -= ws_cyc_nseq[pc >> 24][1]; cycles_remaining -= ws_cyc_nseq[reg[REG_PC] >> 24][1];
break; break;
} }
@ -3082,9 +3033,9 @@ arm_loop:
{ {
/* BL offset */ /* BL offset */
arm_decode_branch(); arm_decode_branch();
reg[REG_LR] = pc + 4; reg[REG_LR] = reg[REG_PC] + 4;
arm_pc_offset_update(offset + 8); reg[REG_PC] += offset + 8;
cycles_remaining -= ws_cyc_nseq[pc >> 24][1]; cycles_remaining -= ws_cyc_nseq[reg[REG_PC] >> 24][1];
break; break;
} }
@ -3105,11 +3056,10 @@ arm_loop:
default: default:
// After SWI, we read bios[0xE4] // After SWI, we read bios[0xE4]
reg[REG_BUS_VALUE] = 0xe3a02004; reg[REG_BUS_VALUE] = 0xe3a02004;
REG_MODE(MODE_SUPERVISOR)[6] = pc + 4; REG_MODE(MODE_SUPERVISOR)[6] = reg[REG_PC] + 4;
collapse_flags(); collapse_flags();
REG_SPSR(MODE_SUPERVISOR) = reg[REG_CPSR]; REG_SPSR(MODE_SUPERVISOR) = reg[REG_CPSR];
reg[REG_PC] = 0x00000008; reg[REG_PC] = 0x00000008;
arm_update_pc();
// Move to ARM mode, Supervisor mode and disable IRQs // Move to ARM mode, Supervisor mode and disable IRQs
reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13 | 0x80; reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13 | 0x80;
set_cpu_mode(MODE_SUPERVISOR); set_cpu_mode(MODE_SUPERVISOR);
@ -3122,9 +3072,9 @@ arm_loop:
skip_instruction: skip_instruction:
/* End of Execute ARM instruction */ /* End of Execute ARM instruction */
cycles_remaining -= ws_cyc_seq[(pc >> 24) & 0xF][1]; cycles_remaining -= ws_cyc_seq[(reg[REG_PC] >> 24) & 0xF][1];
if (pc == idle_loop_target_pc && cycles_remaining > 0) cycles_remaining = 0; if (reg[REG_PC] == idle_loop_target_pc && cycles_remaining > 0) cycles_remaining = 0;
if (cpu_alert & (CPU_ALERT_HALT | CPU_ALERT_IRQ)) if (cpu_alert & (CPU_ALERT_HALT | CPU_ALERT_IRQ))
goto alert; goto alert;
@ -3145,17 +3095,15 @@ thumb_loop:
collapse_flags(); collapse_flags();
/* Process cheats if we are about to execute the cheat hook */ /* Process cheats if we are about to execute the cheat hook */
if (pc == cheat_master_hook) if (reg[REG_PC] == cheat_master_hook)
process_cheats(); process_cheats();
old_pc = pc;
/* Execute THUMB instruction */ /* Execute THUMB instruction */
using_instruction(thumb); using_instruction(thumb);
check_pc_region(); check_pc_region();
pc &= ~0x01; reg[REG_PC] &= ~0x01;
opcode = readaddress16(pc_address_block, (pc & 0x7FFF)); opcode = readaddress16(pc_address_block, (reg[REG_PC] & 0x7FFF));
#ifdef TRACE_INSTRUCTIONS #ifdef TRACE_INSTRUCTIONS
interp_trace_instruction(pc, 0); interp_trace_instruction(pc, 0);
@ -3354,13 +3302,12 @@ thumb_loop:
src = reg[rs]; src = reg[rs];
if(src & 0x01) if(src & 0x01)
{ {
src -= 1; reg[REG_PC] = src - 1;
thumb_pc_offset_update_direct(src);
} }
else else
{ {
/* Switch to ARM mode */ /* Switch to ARM mode */
thumb_pc_offset_update_direct(src); reg[REG_PC] = src;
reg[REG_CPSR] &= ~0x20; reg[REG_CPSR] &= ~0x20;
collapse_flags(); collapse_flags();
goto arm_loop; goto arm_loop;
@ -3370,7 +3317,7 @@ thumb_loop:
case 0x48 ... 0x4F: case 0x48 ... 0x4F:
/* LDR r0..7, [pc + imm] */ /* LDR r0..7, [pc + imm] */
thumb_access_memory(load, imm, ((pc-2) & ~2) + (imm * 4) + 4, reg[(opcode >> 8) & 7], u32); thumb_access_memory(load, imm, ((reg[REG_PC] - 2) & ~2) + (imm * 4) + 4, reg[(opcode >> 8) & 7], u32);
break; break;
case 0x50: case 0x50:
@ -3463,7 +3410,7 @@ thumb_loop:
case 0xA0 ... 0xA7: case 0xA0 ... 0xA7:
/* ADD r0..7, pc, +imm */ /* ADD r0..7, pc, +imm */
thumb_add_noflags(imm, ((opcode >> 8) & 7), (pc & ~2) + 4, (imm * 4)); thumb_add_noflags(imm, ((opcode >> 8) & 7), (reg[REG_PC] & ~2) + 4, (imm * 4));
break; break;
case 0xA8 ... 0xAF: case 0xA8 ... 0xAF:
@ -3597,10 +3544,9 @@ thumb_loop:
default: default:
// After SWI, we read bios[0xE4] // After SWI, we read bios[0xE4]
reg[REG_BUS_VALUE] = 0xe3a02004; reg[REG_BUS_VALUE] = 0xe3a02004;
REG_MODE(MODE_SUPERVISOR)[6] = pc + 2; REG_MODE(MODE_SUPERVISOR)[6] = reg[REG_PC] + 2;
REG_SPSR(MODE_SUPERVISOR) = reg[REG_CPSR]; REG_SPSR(MODE_SUPERVISOR) = reg[REG_CPSR];
reg[REG_PC] = 0x00000008; reg[REG_PC] = 0x00000008;
thumb_update_pc();
// Move to ARM mode, Supervisor mode and disable IRQs // Move to ARM mode, Supervisor mode and disable IRQs
reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13 | 0x80; reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13 | 0x80;
set_cpu_mode(MODE_SUPERVISOR); set_cpu_mode(MODE_SUPERVISOR);
@ -3614,8 +3560,9 @@ thumb_loop:
{ {
/* B label */ /* B label */
thumb_decode_branch(); thumb_decode_branch();
thumb_pc_offset_update(((s32)(offset << 21) >> 20) + 4); s32 br_offset = ((s32)(offset << 21) >> 20) + 4;
cycles_remaining -= ws_cyc_nseq[pc >> 24][0]; reg[REG_PC] += br_offset;
cycles_remaining -= ws_cyc_nseq[reg[REG_PC] >> 24][0];
break; break;
} }
@ -3623,7 +3570,7 @@ thumb_loop:
{ {
/* (low word) BL label */ /* (low word) BL label */
thumb_decode_branch(); thumb_decode_branch();
reg[REG_LR] = pc + 4 + ((s32)(offset << 21) >> 9); reg[REG_LR] = reg[REG_PC] + 4 + ((s32)(offset << 21) >> 9);
thumb_pc_offset(2); thumb_pc_offset(2);
break; break;
} }
@ -3632,19 +3579,19 @@ thumb_loop:
{ {
/* (high word) BL label */ /* (high word) BL label */
thumb_decode_branch(); thumb_decode_branch();
u32 lr = (pc + 2) | 0x01; u32 newlr = (reg[REG_PC] + 2) | 0x01;
pc = reg[REG_LR] + (offset * 2); u32 newpc = reg[REG_LR] + (offset * 2);
reg[REG_LR] = lr; reg[REG_LR] = newlr;
reg[REG_PC] = pc; reg[REG_PC] = newpc;
cycles_remaining -= ws_cyc_nseq[pc >> 24][0]; cycles_remaining -= ws_cyc_nseq[newpc >> 24][0];
break; break;
} }
} }
/* End of Execute THUMB instruction */ /* End of Execute THUMB instruction */
cycles_remaining -= ws_cyc_seq[(pc >> 24) & 0xF][0]; cycles_remaining -= ws_cyc_seq[(reg[REG_PC] >> 24) & 0xF][0];
if (pc == idle_loop_target_pc && cycles_remaining > 0) cycles_remaining = 0; if (reg[REG_PC] == idle_loop_target_pc && cycles_remaining > 0) cycles_remaining = 0;
if (cpu_alert & (CPU_ALERT_HALT | CPU_ALERT_IRQ)) if (cpu_alert & (CPU_ALERT_HALT | CPU_ALERT_IRQ))
goto alert; goto alert;