diff --git a/src/frontend/A32/translate/translate_arm/synchronization.cpp b/src/frontend/A32/translate/translate_arm/synchronization.cpp index 5b5ca96f..09424b5d 100644 --- a/src/frontend/A32/translate/translate_arm/synchronization.cpp +++ b/src/frontend/A32/translate/translate_arm/synchronization.cpp @@ -8,151 +8,200 @@ namespace Dynarmic::A32 { +// CLREX bool ArmTranslatorVisitor::arm_CLREX() { - // CLREX ir.ClearExclusive(); return true; } -bool ArmTranslatorVisitor::arm_LDREX(Cond cond, Reg n, Reg d) { - if (d == Reg::PC || n == Reg::PC) +// LDREX , [] +bool ArmTranslatorVisitor::arm_LDREX(Cond cond, Reg n, Reg t) { + if (t == Reg::PC || n == Reg::PC) { return UnpredictableInstruction(); - // LDREX , [] - if (ConditionPassed(cond)) { - auto address = ir.GetRegister(n); - ir.SetExclusive(address, 4); - ir.SetRegister(d, ir.ReadMemory32(address)); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto address = ir.GetRegister(n); + ir.SetExclusive(address, 4); + ir.SetRegister(t, ir.ReadMemory32(address)); return true; } -bool ArmTranslatorVisitor::arm_LDREXB(Cond cond, Reg n, Reg d) { - if (d == Reg::PC || n == Reg::PC) +// LDREXB , [] +bool ArmTranslatorVisitor::arm_LDREXB(Cond cond, Reg n, Reg t) { + if (t == Reg::PC || n == Reg::PC) { return UnpredictableInstruction(); - // LDREXB , [] - if (ConditionPassed(cond)) { - auto address = ir.GetRegister(n); - ir.SetExclusive(address, 1); - ir.SetRegister(d, ir.ZeroExtendByteToWord(ir.ReadMemory8(address))); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto address = ir.GetRegister(n); + ir.SetExclusive(address, 1); + ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ReadMemory8(address))); return true; } -bool ArmTranslatorVisitor::arm_LDREXD(Cond cond, Reg n, Reg d) { - if (d == Reg::LR || d == Reg::PC || n == Reg::PC) +// LDREXD , , [] +bool ArmTranslatorVisitor::arm_LDREXD(Cond cond, Reg n, Reg t) { + if (t == Reg::LR || t == Reg::PC || n == Reg::PC) { return UnpredictableInstruction(); - // LDREXD , , [] - if (ConditionPassed(cond)) { - auto address = ir.GetRegister(n); - ir.SetExclusive(address, 8); - // DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR - auto lo = ir.ReadMemory32(address); - ir.SetRegister(d, lo); - auto hi = ir.ReadMemory32(ir.Add(address, ir.Imm32(4))); - ir.SetRegister(d+1, hi); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto address = ir.GetRegister(n); + ir.SetExclusive(address, 8); + + // DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR + const auto lo = ir.ReadMemory32(address); + ir.SetRegister(t, lo); + const auto hi = ir.ReadMemory32(ir.Add(address, ir.Imm32(4))); + ir.SetRegister(t+1, hi); return true; } -bool ArmTranslatorVisitor::arm_LDREXH(Cond cond, Reg n, Reg d) { - if (d == Reg::PC || n == Reg::PC) +// LDREXH , [] +bool ArmTranslatorVisitor::arm_LDREXH(Cond cond, Reg n, Reg t) { + if (t == Reg::PC || n == Reg::PC) { return UnpredictableInstruction(); - // LDREXH , [] - if (ConditionPassed(cond)) { - auto address = ir.GetRegister(n); - ir.SetExclusive(address, 2); - ir.SetRegister(d, ir.ZeroExtendHalfToWord(ir.ReadMemory16(address))); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto address = ir.GetRegister(n); + ir.SetExclusive(address, 2); + ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ReadMemory16(address))); return true; } -bool ArmTranslatorVisitor::arm_STREX(Cond cond, Reg n, Reg d, Reg m) { - if (n == Reg::PC || d == Reg::PC || m == Reg::PC) +// STREX , , [] +bool ArmTranslatorVisitor::arm_STREX(Cond cond, Reg n, Reg d, Reg t) { + if (n == Reg::PC || d == Reg::PC || t == Reg::PC) { return UnpredictableInstruction(); - if (d == n || d == m) - return UnpredictableInstruction(); - // STREX , , [] - if (ConditionPassed(cond)) { - auto address = ir.GetRegister(n); - auto value = ir.GetRegister(m); - auto passed = ir.ExclusiveWriteMemory32(address, value); - ir.SetRegister(d, passed); } + + if (d == n || d == t) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto address = ir.GetRegister(n); + const auto value = ir.GetRegister(t); + const auto passed = ir.ExclusiveWriteMemory32(address, value); + ir.SetRegister(d, passed); return true; } -bool ArmTranslatorVisitor::arm_STREXB(Cond cond, Reg n, Reg d, Reg m) { - if (n == Reg::PC || d == Reg::PC || m == Reg::PC) +// STREXB , , [] +bool ArmTranslatorVisitor::arm_STREXB(Cond cond, Reg n, Reg d, Reg t) { + if (n == Reg::PC || d == Reg::PC || t == Reg::PC) { return UnpredictableInstruction(); - if (d == n || d == m) - return UnpredictableInstruction(); - // STREXB , , [] - if (ConditionPassed(cond)) { - auto address = ir.GetRegister(n); - auto value = ir.LeastSignificantByte(ir.GetRegister(m)); - auto passed = ir.ExclusiveWriteMemory8(address, value); - ir.SetRegister(d, passed); } + + if (d == n || d == t) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto address = ir.GetRegister(n); + const auto value = ir.LeastSignificantByte(ir.GetRegister(t)); + const auto passed = ir.ExclusiveWriteMemory8(address, value); + ir.SetRegister(d, passed); return true; } -bool ArmTranslatorVisitor::arm_STREXD(Cond cond, Reg n, Reg d, Reg m) { - if (n == Reg::PC || d == Reg::PC || m == Reg::LR || static_cast(m) % 2 == 1) +// STREXD , , , [] +bool ArmTranslatorVisitor::arm_STREXD(Cond cond, Reg n, Reg d, Reg t) { + if (n == Reg::PC || d == Reg::PC || t == Reg::LR || static_cast(t) % 2 == 1) { return UnpredictableInstruction(); - if (d == n || d == m || d == m+1) - return UnpredictableInstruction(); - Reg m2 = m + 1; - // STREXD , , , [] - if (ConditionPassed(cond)) { - auto address = ir.GetRegister(n); - auto value_lo = ir.GetRegister(m); - auto value_hi = ir.GetRegister(m2); - auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi); - ir.SetRegister(d, passed); } + + if (d == n || d == t || d == t+1) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + const Reg t2 = t + 1; + const auto address = ir.GetRegister(n); + const auto value_lo = ir.GetRegister(t); + const auto value_hi = ir.GetRegister(t2); + const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi); + ir.SetRegister(d, passed); return true; } -bool ArmTranslatorVisitor::arm_STREXH(Cond cond, Reg n, Reg d, Reg m) { - if (n == Reg::PC || d == Reg::PC || m == Reg::PC) +// STREXH , , [] +bool ArmTranslatorVisitor::arm_STREXH(Cond cond, Reg n, Reg d, Reg t) { + if (n == Reg::PC || d == Reg::PC || t == Reg::PC) { return UnpredictableInstruction(); - if (d == n || d == m) - return UnpredictableInstruction(); - // STREXH , , [] - if (ConditionPassed(cond)) { - auto address = ir.GetRegister(n); - auto value = ir.LeastSignificantHalf(ir.GetRegister(m)); - auto passed = ir.ExclusiveWriteMemory16(address, value); - ir.SetRegister(d, passed); } + + if (d == n || d == t) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto address = ir.GetRegister(n); + const auto value = ir.LeastSignificantHalf(ir.GetRegister(t)); + const auto passed = ir.ExclusiveWriteMemory16(address, value); + ir.SetRegister(d, passed); return true; } +// SWP , , [] +// TODO: UNDEFINED if current mode is Hypervisor bool ArmTranslatorVisitor::arm_SWP(Cond cond, Reg n, Reg t, Reg t2) { - if (t == Reg::PC || t2 == Reg::PC || n == Reg::PC || n == t || n == t2) + if (t == Reg::PC || t2 == Reg::PC || n == Reg::PC || n == t || n == t2) { return UnpredictableInstruction(); - // TODO: UNDEFINED if current mode is Hypervisor - // SWP , , [] - if (ConditionPassed(cond)) { - auto data = ir.ReadMemory32(ir.GetRegister(n)); - ir.WriteMemory32(ir.GetRegister(n), ir.GetRegister(t2)); - // TODO: Alignment check - ir.SetRegister(t, data); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto data = ir.ReadMemory32(ir.GetRegister(n)); + ir.WriteMemory32(ir.GetRegister(n), ir.GetRegister(t2)); + // TODO: Alignment check + ir.SetRegister(t, data); return true; } +// SWPB , , [] +// TODO: UNDEFINED if current mode is Hypervisor bool ArmTranslatorVisitor::arm_SWPB(Cond cond, Reg n, Reg t, Reg t2) { - if (t == Reg::PC || t2 == Reg::PC || n == Reg::PC || n == t || n == t2) + if (t == Reg::PC || t2 == Reg::PC || n == Reg::PC || n == t || n == t2) { return UnpredictableInstruction(); - // TODO: UNDEFINED if current mode is Hypervisor - // SWPB , , [] - if (ConditionPassed(cond)) { - auto data = ir.ReadMemory8(ir.GetRegister(n)); - ir.WriteMemory8(ir.GetRegister(n), ir.LeastSignificantByte(ir.GetRegister(t2))); - // TODO: Alignment check - ir.SetRegister(t, ir.ZeroExtendByteToWord(data)); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto data = ir.ReadMemory8(ir.GetRegister(n)); + ir.WriteMemory8(ir.GetRegister(n), ir.LeastSignificantByte(ir.GetRegister(t2))); + // TODO: Alignment check + ir.SetRegister(t, ir.ZeroExtendByteToWord(data)); return true; } diff --git a/src/frontend/A32/translate/translate_arm/translate_arm.h b/src/frontend/A32/translate/translate_arm/translate_arm.h index 63d7071e..0f7613a2 100644 --- a/src/frontend/A32/translate/translate_arm/translate_arm.h +++ b/src/frontend/A32/translate/translate_arm/translate_arm.h @@ -313,16 +313,16 @@ struct ArmTranslatorVisitor final { // Synchronization Primitive instructions bool arm_CLREX(); - bool arm_LDREX(Cond cond, Reg n, Reg d); - bool arm_LDREXB(Cond cond, Reg n, Reg d); - bool arm_LDREXD(Cond cond, Reg n, Reg d); - bool arm_LDREXH(Cond cond, Reg n, Reg d); - bool arm_STREX(Cond cond, Reg n, Reg d, Reg m); - bool arm_STREXB(Cond cond, Reg n, Reg d, Reg m); - bool arm_STREXD(Cond cond, Reg n, Reg d, Reg m); - bool arm_STREXH(Cond cond, Reg n, Reg d, Reg m); - bool arm_SWP(Cond cond, Reg n, Reg d, Reg m); - bool arm_SWPB(Cond cond, Reg n, Reg d, Reg m); + bool arm_LDREX(Cond cond, Reg n, Reg t); + bool arm_LDREXB(Cond cond, Reg n, Reg t); + bool arm_LDREXD(Cond cond, Reg n, Reg t); + bool arm_LDREXH(Cond cond, Reg n, Reg t); + bool arm_STREX(Cond cond, Reg n, Reg d, Reg t); + bool arm_STREXB(Cond cond, Reg n, Reg d, Reg t); + bool arm_STREXD(Cond cond, Reg n, Reg d, Reg t); + bool arm_STREXH(Cond cond, Reg n, Reg d, Reg t); + bool arm_SWP(Cond cond, Reg n, Reg t, Reg t2); + bool arm_SWPB(Cond cond, Reg n, Reg t, Reg t2); // Status register access instructions bool arm_CPS();