From 2e420aba3c007bff84988cf1c281db73c12c7f9a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 29 Jul 2015 04:13:46 -0400 Subject: dyncom: Handle the case where PC is the source register for STR/VSTM/VLDM --- src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 7 +++- src/core/arm/skyeye_common/vfp/vfpinstr.cpp | 54 ++++++++++++++++---------- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 0c20c2bc..759ef728 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -5997,7 +5997,12 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { ldst_inst* inst_cream = (ldst_inst*)inst_base->component; 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->Reg[15] += cpu->GetInstructionSize(); diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp index 9b99fc5b..49298d7b 100644 --- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp @@ -1511,19 +1511,26 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vstm)(unsigned int inst, int index) #ifdef VFP_INTERPRETER_IMPL 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; - vstm_inst *inst_cream = (vstm_inst *)inst_base->component; + vstm_inst* inst_cream = (vstm_inst*)inst_base->component; + + u32 address = cpu->Reg[inst_cream->n]; - addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32); + // 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++) { if (inst_cream->single) { - cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]); - addr += 4; + cpu->WriteMemory32(address, cpu->ExtReg[inst_cream->d+i]); + address += 4; } else { @@ -1531,17 +1538,17 @@ VSTM_INST: /* encoding 1 */ const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; if (cpu->InBigEndianMode()) { - cpu->WriteMemory32(addr + 0, word2); - cpu->WriteMemory32(addr + 4, word1); + cpu->WriteMemory32(address + 0, word2); + cpu->WriteMemory32(address + 4, word1); } else { - cpu->WriteMemory32(addr + 0, word1); - cpu->WriteMemory32(addr + 4, word2); + cpu->WriteMemory32(address + 0, word1); + 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->imm32); } @@ -1731,24 +1738,31 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vldm)(unsigned int inst, int index) #ifdef VFP_INTERPRETER_IMPL 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; - vldm_inst *inst_cream = (vldm_inst *)inst_base->component; + vldm_inst* inst_cream = (vldm_inst*)inst_base->component; + + 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; - addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32); + if (inst_cream->add == 0) + address -= inst_cream->imm32; for (unsigned int i = 0; i < inst_cream->regs; i++) { if (inst_cream->single) { - cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr); - addr += 4; + cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(address); + address += 4; } else { - const u32 word1 = cpu->ReadMemory32(addr + 0); - const u32 word2 = cpu->ReadMemory32(addr + 4); + const u32 word1 = cpu->ReadMemory32(address + 0); + const u32 word2 = cpu->ReadMemory32(address + 4); if (cpu->InBigEndianMode()) { cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; @@ -1758,10 +1772,10 @@ VLDM_INST: 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->imm32); } -- cgit v1.2.3