[Interp] Improve sbit emulation for LDM

This commit is contained in:
David Guillen Fandos 2023-11-13 21:08:58 +01:00
parent beb6e4b520
commit f0f0b57c56
1 changed files with 93 additions and 74 deletions

167
cpu.cc
View File

@ -595,7 +595,6 @@ const u8 bit_count[256] =
} \
#define arm_spsr_restore() \
if(rd == 15) \
{ \
if(reg[CPU_MODE] != MODE_USER && reg[CPU_MODE] != MODE_SYSTEM) \
{ \
@ -609,6 +608,18 @@ const u8 bit_count[256] =
goto thumb_loop; \
} \
#define arm_spsr_restore_check() \
if(rd == REG_PC) \
{ \
arm_spsr_restore() \
} \
#define arm_spsr_restore_ldm_check() \
if (opcode & 0x8000) /* PC is in the LDM reg list */ \
{ \
arm_spsr_restore() \
} \
#define arm_data_proc_flags_reg() \
arm_decode_data_proc_reg(opcode); \
calculate_reg_sh_flags() \
@ -648,7 +659,7 @@ const u8 bit_count[256] =
calculate_flags_logic(dest); \
arm_pc_offset(-4); \
reg[rd] = dest; \
arm_spsr_restore(); \
arm_spsr_restore_check(); \
} \
#define arm_data_proc_add_flags(src_a, src_b, src_c, type) \
@ -664,7 +675,7 @@ const u8 bit_count[256] =
calculate_flags_add(dest, _sa, _sb); \
arm_pc_offset(-4); \
reg[rd] = dest; \
arm_spsr_restore(); \
arm_spsr_restore_check(); \
}
#define arm_data_proc_sub_flags(src_a, src_b, src_c, type) \
@ -677,7 +688,7 @@ const u8 bit_count[256] =
calculate_flags_sub(dest, _sa, _sb, _sc); \
arm_pc_offset(-4); \
reg[rd] = dest; \
arm_spsr_restore(); \
arm_spsr_restore_check(); \
} \
#define arm_data_proc_test_logic(expr, type) \
@ -971,7 +982,7 @@ inline cpu_alert_type exec_arm_block_mem(u32 rn, u32 reglist, s32 &cycles_remain
// However for LDM {PC} we restore CPSR from SPSR.
// TODO: implement CPSR restore, only USER mode is now implemented.
u32 old_cpsr = reg[REG_CPSR];
if (sbit)
if (sbit && (mode == AccStore || rn != REG_PC))
set_cpu_mode(MODE_USER);
// If base is in the reglist and writeback is enabled, the value of the
@ -1010,7 +1021,7 @@ inline cpu_alert_type exec_arm_block_mem(u32 rn, u32 reglist, s32 &cycles_remain
if (writeback && !writeback_first)
reg[rn] = endaddr;
if (sbit)
if (sbit && (mode == AccStore || rn != REG_PC))
set_cpu_mode(cpu_modes[old_cpsr & 0xF]);
return cpu_alert;
@ -2857,65 +2868,65 @@ arm_loop:
cpu_alert |= exec_arm_block_mem<AccStore, false, false, AddrDec, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x82: /* STMDA rn!, rlist */
cpu_alert |= exec_arm_block_mem<AccStore, true, false, AddrDec, AddrUpdPost>(
case 0x88: /* STMIA rn, rlist */
cpu_alert |= exec_arm_block_mem<AccStore, false, false, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x84: /* STMDA rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, false, true, AddrDec, AddrUpdPost>(
case 0x90: /* STMDB rn, rlist */
cpu_alert |= exec_arm_block_mem<AccStore, false, false, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x86: /* STMDA rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, true, true, AddrDec, AddrUpdPost>(
case 0x98: /* STMIB rn, rlist */
cpu_alert |= exec_arm_block_mem<AccStore, false, false, AddrInc, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x88: /* STMIA rn, rlist */
cpu_alert |= exec_arm_block_mem<AccStore, false, false, AddrInc, AddrUpdPost>(
case 0x82: /* STMDA rn!, rlist */
cpu_alert |= exec_arm_block_mem<AccStore, true, false, AddrDec, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x8A: /* STMIA rn!, rlist */
cpu_alert |= exec_arm_block_mem<AccStore, true, false, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x8C: /* STMIA rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, false, true, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x8E: /* STMIA rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, true, true, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x90: /* STMDB rn, rlist */
cpu_alert |= exec_arm_block_mem<AccStore, false, false, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x92: /* STMDB rn!, rlist */
cpu_alert |= exec_arm_block_mem<AccStore, true, false, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x94: /* STMDB rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, false, true, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x96: /* STMDB rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, true, true, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x98: /* STMIB rn, rlist */
cpu_alert |= exec_arm_block_mem<AccStore, false, false, AddrInc, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x9A: /* STMIB rn!, rlist */
cpu_alert |= exec_arm_block_mem<AccStore, true, false, AddrInc, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x84: /* STMDA rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, false, true, AddrDec, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x8C: /* STMIA rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, false, true, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x94: /* STMDB rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, false, true, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x9C: /* STMIB rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, false, true, AddrInc, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x86: /* STMDA rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, true, true, AddrDec, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x8E: /* STMIA rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, true, true, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x96: /* STMDB rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, true, true, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x9E: /* STMIB rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccStore, true, true, AddrInc, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
@ -2928,68 +2939,76 @@ arm_loop:
cpu_alert |= exec_arm_block_mem<AccLoad, false, false, AddrDec, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x83: /* LDMDA rn!, rlist */
cpu_alert |= exec_arm_block_mem<AccLoad, true, false, AddrDec, AddrUpdPost>(
case 0x89: /* LDMIA rn, rlist */
cpu_alert |= exec_arm_block_mem<AccLoad, false, false, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x85: /* LDMDA rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, false, true, AddrDec, AddrUpdPost>(
case 0x91: /* LDMDB rn, rlist */
cpu_alert |= exec_arm_block_mem<AccLoad, false, false, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x87: /* LDMDA rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, true, true, AddrDec, AddrUpdPost>(
case 0x99: /* LDMIB rn, rlist */
cpu_alert |= exec_arm_block_mem<AccLoad, false, false, AddrInc, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x89: /* LDMIA rn, rlist */
cpu_alert |= exec_arm_block_mem<AccLoad, false, false, AddrInc, AddrUpdPost>(
case 0x83: /* LDMDA rn!, rlist */
cpu_alert |= exec_arm_block_mem<AccLoad, true, false, AddrDec, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x8B: /* LDMIA rn!, rlist */
cpu_alert |= exec_arm_block_mem<AccLoad, true, false, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x8D: /* LDMIA rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, false, true, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x8F: /* LDMIA rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, true, true, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x91: /* LDMDB rn, rlist */
cpu_alert |= exec_arm_block_mem<AccLoad, false, false, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x93: /* LDMDB rn!, rlist */
cpu_alert |= exec_arm_block_mem<AccLoad, true, false, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x95: /* LDMDB rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, false, true, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x97: /* LDMDB rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, true, true, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x99: /* LDMIB rn, rlist */
cpu_alert |= exec_arm_block_mem<AccLoad, false, false, AddrInc, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x9B: /* LDMIB rn!, rlist */
cpu_alert |= exec_arm_block_mem<AccLoad, true, false, AddrInc, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
break;
case 0x85: /* LDMDA rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, false, true, AddrDec, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
arm_spsr_restore_ldm_check();
break;
case 0x8D: /* LDMIA rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, false, true, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
arm_spsr_restore_ldm_check();
break;
case 0x95: /* LDMDB rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, false, true, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
arm_spsr_restore_ldm_check();
break;
case 0x9D: /* LDMIB rn, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, false, true, AddrInc, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
arm_spsr_restore_ldm_check();
break;
case 0x87: /* LDMDA rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, true, true, AddrDec, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
arm_spsr_restore_ldm_check();
break;
case 0x8F: /* LDMIA rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, true, true, AddrInc, AddrUpdPost>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
arm_spsr_restore_ldm_check();
break;
case 0x97: /* LDMDB rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, true, true, AddrDec, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
arm_spsr_restore_ldm_check();
break;
case 0x9F: /* LDMIB rn!, rlist^ */
cpu_alert |= exec_arm_block_mem<AccLoad, true, true, AddrInc, AddrUpdPre>(
(opcode >> 16) & 0x0F, opcode & 0xFFFF, cycles_remaining);
arm_spsr_restore_ldm_check();
break;