diff --git a/src/frontend/decoder/arm.h b/src/frontend/decoder/arm.h index 10017d87..ddda1e1e 100644 --- a/src/frontend/decoder/arm.h +++ b/src/frontend/decoder/arm.h @@ -183,8 +183,8 @@ boost::optional&> DecodeArm(u32 instruction) { INST(&V::arm_LDRB_reg, "LDRB (reg)", "cccc011pu1w1nnnnddddvvvvvrr0mmmm"), //INST(&V::arm_LDRBT, "LDRBT (A1)", "cccc0100u111nnnnttttvvvvvvvvvvvv"), //INST(&V::arm_LDRBT, "LDRBT (A2)", "cccc0110u111nnnnttttvvvvvrr0mmmm"), - //INST(&V::arm_LDRD_imm, "LDRD (imm)", "cccc000pu1w0nnnnddddvvvv1101vvvv"), // v5E - //INST(&V::arm_LDRD_reg, "LDRD (reg)", "cccc000pu0w0nnnndddd00001101mmmm"), // v5E + INST(&V::arm_LDRD_imm, "LDRD (imm)", "cccc000pu1w0nnnnddddvvvv1101vvvv"), // v5E + INST(&V::arm_LDRD_reg, "LDRD (reg)", "cccc000pu0w0nnnndddd00001101mmmm"), // v5E INST(&V::arm_LDRH_imm, "LDRH (imm)", "cccc000pu1w1nnnnddddvvvv1011vvvv"), INST(&V::arm_LDRH_reg, "LDRH (reg)", "cccc000pu0w1nnnndddd00001011mmmm"), //INST(&V::arm_LDRHT, "LDRHT (A1)", "----0000-111------------1011----"), diff --git a/src/frontend/translate/translate_arm/load_store.cpp b/src/frontend/translate/translate_arm/load_store.cpp index 47245efd..086e2ed0 100644 --- a/src/frontend/translate/translate_arm/load_store.cpp +++ b/src/frontend/translate/translate_arm/load_store.cpp @@ -109,11 +109,79 @@ bool ArmTranslatorVisitor::arm_LDRBT() { } bool ArmTranslatorVisitor::arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) { - return InterpretThisInstruction(); + if (ConditionPassed(cond)) { + const auto address_a = GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm8a << 4 | imm8b)); + const auto address_b = ir.Add(address_a, ir.Imm32(4)); + auto data_a = ir.ReadMemory32(address_a); + auto data_b = ir.ReadMemory32(address_b); + + switch(d) { + case Reg::PC: + data_a = ir.Add(data_a, ir.Imm32(4)); + break; + case Reg::LR: + data_b = ir.Add(data_b, ir.Imm32(4)); + break; + } + + if (d == Reg::PC) { + ir.ALUWritePC(data_a); + } else { + ir.SetRegister(d, data_a); + } + + const Reg reg_b = static_cast(std::min(d + 1, Reg::R15)); + if (reg_b == Reg::PC) { + ir.ALUWritePC(data_b); + } else { + ir.SetRegister(reg_b, data_b); + } + + if (d == Reg::PC || reg_b == Reg::PC) { + ir.SetTerm(IR::Term::ReturnToDispatch{}); + return false; + } + } + + return true; } bool ArmTranslatorVisitor::arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m) { - return InterpretThisInstruction(); + if (ConditionPassed(cond)) { + const auto address_a = GetAddressingMode(ir, P, U, W, n, ir.GetRegister(m)); + const auto address_b = ir.Add(address_a, ir.Imm32(4)); + auto data_a = ir.ReadMemory32(address_a); + auto data_b = ir.ReadMemory32(address_b); + + switch(d) { + case Reg::PC: + data_a = ir.Add(data_a, ir.Imm32(4)); + break; + case Reg::LR: + data_b = ir.Add(data_b, ir.Imm32(4)); + break; + } + + if (d == Reg::PC) { + ir.ALUWritePC(data_a); + } else { + ir.SetRegister(d, data_a); + } + + const Reg reg_b = static_cast(std::min(d + 1, Reg::R15)); + if (reg_b == Reg::PC) { + ir.ALUWritePC(data_b); + } else { + ir.SetRegister(reg_b, data_b); + } + + if (d == Reg::PC || reg_b == Reg::PC) { + ir.SetTerm(IR::Term::ReturnToDispatch{}); + return false; + } + } + + return true; } bool ArmTranslatorVisitor::arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) {