citra-emu
/
citra-canary
Archived
1
0
Fork 0

dyncom: Handle the case where PC is the source register for STR/VSTM/VLDM

This commit is contained in:
Lioncash 2015-07-29 04:13:46 -04:00
parent 7c7eeb9d34
commit 2e420aba3c
2 changed files with 40 additions and 21 deletions

View File

@ -5997,7 +5997,12 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
ldst_inst* inst_cream = (ldst_inst*)inst_base->component; ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
inst_cream->get_addr(cpu, inst_cream->inst, addr); inst_cream->get_addr(cpu, inst_cream->inst, addr);
unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; unsigned int reg = BITS(inst_cream->inst, 12, 15);
unsigned int value = cpu->Reg[reg];
if (reg == 15)
value += 2 * cpu->GetInstructionSize();
cpu->WriteMemory32(addr, value); cpu->WriteMemory32(addr, value);
} }
cpu->Reg[15] += cpu->GetInstructionSize(); cpu->Reg[15] += cpu->GetInstructionSize();

View File

@ -1511,19 +1511,26 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vstm)(unsigned int inst, int index)
#ifdef VFP_INTERPRETER_IMPL #ifdef VFP_INTERPRETER_IMPL
VSTM_INST: /* encoding 1 */ VSTM_INST: /* encoding 1 */
{ {
if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
CHECK_VFP_ENABLED; CHECK_VFP_ENABLED;
vstm_inst *inst_cream = (vstm_inst *)inst_base->component; vstm_inst* inst_cream = (vstm_inst*)inst_base->component;
addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32); u32 address = cpu->Reg[inst_cream->n];
// Only possible in ARM mode, where PC accesses have an 8 byte offset.
if (inst_cream->n == 15)
address += 8;
if (inst_cream->add == 0)
address -= inst_cream->imm32;
for (unsigned int i = 0; i < inst_cream->regs; i++) for (unsigned int i = 0; i < inst_cream->regs; i++)
{ {
if (inst_cream->single) if (inst_cream->single)
{ {
cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]); cpu->WriteMemory32(address, cpu->ExtReg[inst_cream->d+i]);
addr += 4; address += 4;
} }
else else
{ {
@ -1531,17 +1538,17 @@ VSTM_INST: /* encoding 1 */
const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1];
if (cpu->InBigEndianMode()) { if (cpu->InBigEndianMode()) {
cpu->WriteMemory32(addr + 0, word2); cpu->WriteMemory32(address + 0, word2);
cpu->WriteMemory32(addr + 4, word1); cpu->WriteMemory32(address + 4, word1);
} else { } else {
cpu->WriteMemory32(addr + 0, word1); cpu->WriteMemory32(address + 0, word1);
cpu->WriteMemory32(addr + 4, word2); cpu->WriteMemory32(address + 4, word2);
} }
addr += 8; address += 8;
} }
} }
if (inst_cream->wback){ if (inst_cream->wback) {
cpu->Reg[inst_cream->n] = (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32 : cpu->Reg[inst_cream->n] = (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32 :
cpu->Reg[inst_cream->n] - inst_cream->imm32); cpu->Reg[inst_cream->n] - inst_cream->imm32);
} }
@ -1731,24 +1738,31 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vldm)(unsigned int inst, int index)
#ifdef VFP_INTERPRETER_IMPL #ifdef VFP_INTERPRETER_IMPL
VLDM_INST: VLDM_INST:
{ {
if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
CHECK_VFP_ENABLED; CHECK_VFP_ENABLED;
vldm_inst *inst_cream = (vldm_inst *)inst_base->component; vldm_inst* inst_cream = (vldm_inst*)inst_base->component;
addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32); u32 address = cpu->Reg[inst_cream->n];
// Only possible in ARM mode, where PC accesses have an 8 byte offset.
if (inst_cream->n == 15)
address += 8;
if (inst_cream->add == 0)
address -= inst_cream->imm32;
for (unsigned int i = 0; i < inst_cream->regs; i++) for (unsigned int i = 0; i < inst_cream->regs; i++)
{ {
if (inst_cream->single) if (inst_cream->single)
{ {
cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr); cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(address);
addr += 4; address += 4;
} }
else else
{ {
const u32 word1 = cpu->ReadMemory32(addr + 0); const u32 word1 = cpu->ReadMemory32(address + 0);
const u32 word2 = cpu->ReadMemory32(addr + 4); const u32 word2 = cpu->ReadMemory32(address + 4);
if (cpu->InBigEndianMode()) { if (cpu->InBigEndianMode()) {
cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; cpu->ExtReg[(inst_cream->d+i)*2+0] = word2;
@ -1758,10 +1772,10 @@ VLDM_INST:
cpu->ExtReg[(inst_cream->d+i)*2+1] = word2; cpu->ExtReg[(inst_cream->d+i)*2+1] = word2;
} }
addr += 8; address += 8;
} }
} }
if (inst_cream->wback){ if (inst_cream->wback) {
cpu->Reg[inst_cream->n] = (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32 : cpu->Reg[inst_cream->n] = (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32 :
cpu->Reg[inst_cream->n] - inst_cream->imm32); cpu->Reg[inst_cream->n] - inst_cream->imm32);
} }