translate_arm/synchronization: Invert conditionals where applicable

This commit is contained in:
Lioncash 2019-03-01 02:21:35 -05:00 committed by MerryMage
parent 9514e3602e
commit e209b31073
2 changed files with 150 additions and 101 deletions

View file

@ -8,151 +8,200 @@
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
// CLREX
bool ArmTranslatorVisitor::arm_CLREX() { bool ArmTranslatorVisitor::arm_CLREX() {
// CLREX
ir.ClearExclusive(); ir.ClearExclusive();
return true; return true;
} }
bool ArmTranslatorVisitor::arm_LDREX(Cond cond, Reg n, Reg d) { // LDREX<c> <Rt>, [<Rn>]
if (d == Reg::PC || n == Reg::PC) bool ArmTranslatorVisitor::arm_LDREX(Cond cond, Reg n, Reg t) {
if (t == Reg::PC || n == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
// LDREX <Rd>, [<Rn>]
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; return true;
} }
bool ArmTranslatorVisitor::arm_LDREXB(Cond cond, Reg n, Reg d) { // LDREXB<c> <Rt>, [<Rn>]
if (d == Reg::PC || n == Reg::PC) bool ArmTranslatorVisitor::arm_LDREXB(Cond cond, Reg n, Reg t) {
if (t == Reg::PC || n == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
// LDREXB <Rd>, [<Rn>]
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; return true;
} }
bool ArmTranslatorVisitor::arm_LDREXD(Cond cond, Reg n, Reg d) { // LDREXD<c> <Rt>, <Rt2>, [<Rn>]
if (d == Reg::LR || d == Reg::PC || n == Reg::PC) bool ArmTranslatorVisitor::arm_LDREXD(Cond cond, Reg n, Reg t) {
if (t == Reg::LR || t == Reg::PC || n == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
// LDREXD <Rd>, <Rd1>, [<Rn>]
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; return true;
} }
bool ArmTranslatorVisitor::arm_LDREXH(Cond cond, Reg n, Reg d) { // LDREXH<c> <Rt>, [<Rn>]
if (d == Reg::PC || n == Reg::PC) bool ArmTranslatorVisitor::arm_LDREXH(Cond cond, Reg n, Reg t) {
if (t == Reg::PC || n == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
// LDREXH <Rd>, [<Rn>]
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; return true;
} }
bool ArmTranslatorVisitor::arm_STREX(Cond cond, Reg n, Reg d, Reg m) { // STREX<c> <Rd>, <Rt>, [<Rn>]
if (n == Reg::PC || d == Reg::PC || m == Reg::PC) bool ArmTranslatorVisitor::arm_STREX(Cond cond, Reg n, Reg d, Reg t) {
if (n == Reg::PC || d == Reg::PC || t == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (d == n || d == m)
return UnpredictableInstruction();
// STREX <Rd>, <Rm>, [<Rn>]
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; return true;
} }
bool ArmTranslatorVisitor::arm_STREXB(Cond cond, Reg n, Reg d, Reg m) { // STREXB<c> <Rd>, <Rt>, [<Rn>]
if (n == Reg::PC || d == Reg::PC || m == Reg::PC) bool ArmTranslatorVisitor::arm_STREXB(Cond cond, Reg n, Reg d, Reg t) {
if (n == Reg::PC || d == Reg::PC || t == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (d == n || d == m)
return UnpredictableInstruction();
// STREXB <Rd>, <Rm>, [<Rn>]
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; return true;
} }
bool ArmTranslatorVisitor::arm_STREXD(Cond cond, Reg n, Reg d, Reg m) { // STREXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>]
if (n == Reg::PC || d == Reg::PC || m == Reg::LR || static_cast<size_t>(m) % 2 == 1) bool ArmTranslatorVisitor::arm_STREXD(Cond cond, Reg n, Reg d, Reg t) {
if (n == Reg::PC || d == Reg::PC || t == Reg::LR || static_cast<size_t>(t) % 2 == 1) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (d == n || d == m || d == m+1)
return UnpredictableInstruction();
Reg m2 = m + 1;
// STREXD <Rd>, <Rm>, <Rm2>, [<Rn>]
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; return true;
} }
bool ArmTranslatorVisitor::arm_STREXH(Cond cond, Reg n, Reg d, Reg m) { // STREXH<c> <Rd>, <Rt>, [<Rn>]
if (n == Reg::PC || d == Reg::PC || m == Reg::PC) bool ArmTranslatorVisitor::arm_STREXH(Cond cond, Reg n, Reg d, Reg t) {
if (n == Reg::PC || d == Reg::PC || t == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (d == n || d == m)
return UnpredictableInstruction();
// STREXH <Rd>, <Rm>, [<Rn>]
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; return true;
} }
// SWP<c> <Rt>, <Rt2>, [<Rn>]
// TODO: UNDEFINED if current mode is Hypervisor
bool ArmTranslatorVisitor::arm_SWP(Cond cond, Reg n, Reg t, Reg t2) { 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(); return UnpredictableInstruction();
// TODO: UNDEFINED if current mode is Hypervisor
// SWP <Rt>, <Rt2>, [<Rn>]
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; return true;
} }
// SWPB<c> <Rt>, <Rt2>, [<Rn>]
// TODO: UNDEFINED if current mode is Hypervisor
bool ArmTranslatorVisitor::arm_SWPB(Cond cond, Reg n, Reg t, Reg t2) { 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(); return UnpredictableInstruction();
// TODO: UNDEFINED if current mode is Hypervisor
// SWPB <Rt>, <Rt2>, [<Rn>]
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; return true;
} }

View file

@ -313,16 +313,16 @@ struct ArmTranslatorVisitor final {
// Synchronization Primitive instructions // Synchronization Primitive instructions
bool arm_CLREX(); bool arm_CLREX();
bool arm_LDREX(Cond cond, Reg n, Reg d); bool arm_LDREX(Cond cond, Reg n, Reg t);
bool arm_LDREXB(Cond cond, Reg n, Reg d); bool arm_LDREXB(Cond cond, Reg n, Reg t);
bool arm_LDREXD(Cond cond, Reg n, Reg d); bool arm_LDREXD(Cond cond, Reg n, Reg t);
bool arm_LDREXH(Cond cond, Reg n, Reg d); bool arm_LDREXH(Cond cond, Reg n, Reg t);
bool arm_STREX(Cond cond, Reg n, Reg d, Reg m); bool arm_STREX(Cond cond, Reg n, Reg d, Reg t);
bool arm_STREXB(Cond cond, Reg n, Reg d, Reg m); bool arm_STREXB(Cond cond, Reg n, Reg d, Reg t);
bool arm_STREXD(Cond cond, Reg n, Reg d, Reg m); bool arm_STREXD(Cond cond, Reg n, Reg d, Reg t);
bool arm_STREXH(Cond cond, Reg n, Reg d, Reg m); bool arm_STREXH(Cond cond, Reg n, Reg d, Reg t);
bool arm_SWP(Cond cond, Reg n, Reg d, Reg m); bool arm_SWP(Cond cond, Reg n, Reg t, Reg t2);
bool arm_SWPB(Cond cond, Reg n, Reg d, Reg m); bool arm_SWPB(Cond cond, Reg n, Reg t, Reg t2);
// Status register access instructions // Status register access instructions
bool arm_CPS(); bool arm_CPS();