mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-01-06 22:48:25 +01:00
TranslateArm: Implement CLREX, LDREX, LDREXB, LDREXD, LDREXH, STREX, STREXB, STREXD, STREXH, SWP, SWPB
This commit is contained in:
parent
d921390928
commit
df39308e03
12 changed files with 446 additions and 98 deletions
|
|
@ -181,8 +181,8 @@ std::vector<ArmMatcher<V>> GetArmDecodeTable() {
|
|||
INST(&V::arm_STREXB, "STREXB", "cccc00011100nnnndddd11111001mmmm"), // v6K
|
||||
INST(&V::arm_STREXD, "STREXD", "cccc00011010nnnndddd11111001mmmm"), // v6K
|
||||
INST(&V::arm_STREXH, "STREXH", "cccc00011110nnnndddd11111001mmmm"), // v6K
|
||||
INST(&V::arm_SWP, "SWP", "cccc00010000nnnndddd00001001mmmm"), // v2S (v6: Deprecated)
|
||||
INST(&V::arm_SWPB, "SWPB", "cccc00010100nnnndddd00001001mmmm"), // v2S (v6: Deprecated)
|
||||
INST(&V::arm_SWP, "SWP", "cccc00010000nnnntttt00001001uuuu"), // v2S (v6: Deprecated)
|
||||
INST(&V::arm_SWPB, "SWPB", "cccc00010100nnnntttt00001001uuuu"), // v2S (v6: Deprecated)
|
||||
|
||||
// Load/Store instructions
|
||||
INST(&V::arm_LDR_imm, "LDR (imm)", "cccc010pu0w1nnnnddddvvvvvvvvvvvv"),
|
||||
|
|
|
|||
|
|
@ -697,17 +697,39 @@ public:
|
|||
std::string arm_QDSUB(Cond cond, Reg n, Reg d, Reg m) { return "ice"; }
|
||||
|
||||
// Synchronization Primitive instructions
|
||||
std::string arm_CLREX() { return "ice"; }
|
||||
std::string arm_LDREX(Cond cond, Reg n, Reg d) { return "ice"; }
|
||||
std::string arm_LDREXB(Cond cond, Reg n, Reg d) { return "ice"; }
|
||||
std::string arm_LDREXD(Cond cond, Reg n, Reg d) { return "ice"; }
|
||||
std::string arm_LDREXH(Cond cond, Reg n, Reg d) { return "ice"; }
|
||||
std::string arm_STREX(Cond cond, Reg n, Reg d, Reg m) { return "ice"; }
|
||||
std::string arm_STREXB(Cond cond, Reg n, Reg d, Reg m) { return "ice"; }
|
||||
std::string arm_STREXD(Cond cond, Reg n, Reg d, Reg m) { return "ice"; }
|
||||
std::string arm_STREXH(Cond cond, Reg n, Reg d, Reg m) { return "ice"; }
|
||||
std::string arm_SWP(Cond cond, Reg n, Reg d, Reg m) { return "ice"; }
|
||||
std::string arm_SWPB(Cond cond, Reg n, Reg d, Reg m) { return "ice"; }
|
||||
std::string arm_CLREX() {
|
||||
return "clrex";
|
||||
}
|
||||
std::string arm_LDREX(Cond cond, Reg n, Reg d) {
|
||||
return Common::StringFromFormat("ldrex%s %s, [%s]", CondToString(cond), RegToString(d), RegToString(n));
|
||||
}
|
||||
std::string arm_LDREXB(Cond cond, Reg n, Reg d) {
|
||||
return Common::StringFromFormat("ldrexb%s %s, [%s]", CondToString(cond), RegToString(d), RegToString(n));
|
||||
}
|
||||
std::string arm_LDREXD(Cond cond, Reg n, Reg d) {
|
||||
return Common::StringFromFormat("ldrexd%s %s, %s, [%s]", CondToString(cond), RegToString(d), RegToString(d+1), RegToString(n));
|
||||
}
|
||||
std::string arm_LDREXH(Cond cond, Reg n, Reg d) {
|
||||
return Common::StringFromFormat("ldrexh%s %s, [%s]", CondToString(cond), RegToString(d), RegToString(n));
|
||||
}
|
||||
std::string arm_STREX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
return Common::StringFromFormat("strex%s %s, %s, [%s]", CondToString(cond), RegToString(d), RegToString(m), RegToString(n));
|
||||
}
|
||||
std::string arm_STREXB(Cond cond, Reg n, Reg d, Reg m) {
|
||||
return Common::StringFromFormat("strexb%s %s, %s, [%s]", CondToString(cond), RegToString(d), RegToString(m), RegToString(n));
|
||||
}
|
||||
std::string arm_STREXD(Cond cond, Reg n, Reg d, Reg m) {
|
||||
return Common::StringFromFormat("strexd%s %s, %s, %s, [%s]", CondToString(cond), RegToString(d), RegToString(m), RegToString(m+1), RegToString(n));
|
||||
}
|
||||
std::string arm_STREXH(Cond cond, Reg n, Reg d, Reg m) {
|
||||
return Common::StringFromFormat("strexh%s %s, %s, [%s]", CondToString(cond), RegToString(d), RegToString(m), RegToString(n));
|
||||
}
|
||||
std::string arm_SWP(Cond cond, Reg n, Reg t, Reg t2) {
|
||||
return Common::StringFromFormat("swp%s %s, %s, [%s]", CondToString(cond), RegToString(t), RegToString(t2), RegToString(n));
|
||||
}
|
||||
std::string arm_SWPB(Cond cond, Reg n, Reg t, Reg t2) {
|
||||
return Common::StringFromFormat("swpb%s %s, %s, [%s]", CondToString(cond), RegToString(t), RegToString(t2), RegToString(n));
|
||||
}
|
||||
|
||||
// Status register access instructions
|
||||
std::string arm_CPS() { return "ice"; }
|
||||
|
|
|
|||
|
|
@ -362,6 +362,15 @@ IR::Value IREmitter::FPSub64(const IR::Value& a, const IR::Value& b, bool fpscr_
|
|||
return Inst(IR::Opcode::FPSub64, {a, b});
|
||||
}
|
||||
|
||||
void IREmitter::ClearExlcusive() {
|
||||
Inst(IR::Opcode::ClearExclusive, {});
|
||||
}
|
||||
|
||||
void IREmitter::SetExclusive(const IR::Value& vaddr, size_t byte_size) {
|
||||
ASSERT(byte_size == 1 || byte_size == 2 || byte_size == 4 || byte_size == 8 || byte_size == 16);
|
||||
Inst(IR::Opcode::SetExclusive, {vaddr, Imm8(u8(byte_size))});
|
||||
}
|
||||
|
||||
IR::Value IREmitter::ReadMemory8(const IR::Value& vaddr) {
|
||||
return Inst(IR::Opcode::ReadMemory8, {vaddr});
|
||||
}
|
||||
|
|
@ -412,6 +421,38 @@ void IREmitter::WriteMemory64(const IR::Value& vaddr, const IR::Value& value) {
|
|||
}
|
||||
}
|
||||
|
||||
IR::Value IREmitter::ExclusiveWriteMemory8(const IR::Value& vaddr, const IR::Value& value) {
|
||||
return Inst(IR::Opcode::ExclusiveWriteMemory8, {vaddr, value});
|
||||
}
|
||||
|
||||
IR::Value IREmitter::ExclusiveWriteMemory16(const IR::Value& vaddr, const IR::Value& value) {
|
||||
if (current_location.EFlag()) {
|
||||
auto v = ByteReverseHalf(value);
|
||||
return Inst(IR::Opcode::ExclusiveWriteMemory16, {vaddr, v});
|
||||
} else {
|
||||
return Inst(IR::Opcode::ExclusiveWriteMemory16, {vaddr, value});
|
||||
}
|
||||
}
|
||||
|
||||
IR::Value IREmitter::ExclusiveWriteMemory32(const IR::Value& vaddr, const IR::Value& value) {
|
||||
if (current_location.EFlag()) {
|
||||
auto v = ByteReverseWord(value);
|
||||
return Inst(IR::Opcode::ExclusiveWriteMemory32, {vaddr, v});
|
||||
} else {
|
||||
return Inst(IR::Opcode::ExclusiveWriteMemory32, {vaddr, value});
|
||||
}
|
||||
}
|
||||
|
||||
IR::Value IREmitter::ExclusiveWriteMemory64(const IR::Value& vaddr, const IR::Value& value_lo, const IR::Value& value_hi) {
|
||||
if (current_location.EFlag()) {
|
||||
auto vlo = ByteReverseWord(value_lo);
|
||||
auto vhi = ByteReverseWord(value_hi);
|
||||
return Inst(IR::Opcode::ExclusiveWriteMemory64, {vaddr, vlo, vhi});
|
||||
} else {
|
||||
return Inst(IR::Opcode::ExclusiveWriteMemory64, {vaddr, value_lo, value_hi});
|
||||
}
|
||||
}
|
||||
|
||||
void IREmitter::Breakpoint() {
|
||||
Inst(IR::Opcode::Breakpoint, {});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@ public:
|
|||
IR::Value FPSub32(const IR::Value& a, const IR::Value& b, bool fpscr_controlled);
|
||||
IR::Value FPSub64(const IR::Value& a, const IR::Value& b, bool fpscr_controlled);
|
||||
|
||||
void ClearExlcusive();
|
||||
void SetExclusive(const IR::Value& vaddr, size_t byte_size);
|
||||
IR::Value ReadMemory8(const IR::Value& vaddr);
|
||||
IR::Value ReadMemory16(const IR::Value& vaddr);
|
||||
IR::Value ReadMemory32(const IR::Value& vaddr);
|
||||
|
|
@ -121,6 +123,10 @@ public:
|
|||
void WriteMemory16(const IR::Value& vaddr, const IR::Value& value);
|
||||
void WriteMemory32(const IR::Value& vaddr, const IR::Value& value);
|
||||
void WriteMemory64(const IR::Value& vaddr, const IR::Value& value);
|
||||
IR::Value ExclusiveWriteMemory8(const IR::Value& vaddr, const IR::Value& value);
|
||||
IR::Value ExclusiveWriteMemory16(const IR::Value& vaddr, const IR::Value& value);
|
||||
IR::Value ExclusiveWriteMemory32(const IR::Value& vaddr, const IR::Value& value);
|
||||
IR::Value ExclusiveWriteMemory64(const IR::Value& vaddr, const IR::Value& value_lo, const IR::Value& value_hi);
|
||||
|
||||
void Breakpoint();
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@ OPCODE(FPSub32, T::F32, T::F32, T::F32
|
|||
OPCODE(FPSub64, T::F64, T::F64, T::F64 )
|
||||
|
||||
// Memory access
|
||||
OPCODE(ClearExclusive, T::Void, )
|
||||
OPCODE(SetExclusive, T::Void, T::U32, T::U8 )
|
||||
OPCODE(ReadMemory8, T::U8, T::U32 )
|
||||
OPCODE(ReadMemory16, T::U16, T::U32 )
|
||||
OPCODE(ReadMemory32, T::U32, T::U32 )
|
||||
|
|
@ -90,3 +92,7 @@ OPCODE(WriteMemory8, T::Void, T::U32, T::U8
|
|||
OPCODE(WriteMemory16, T::Void, T::U32, T::U16 )
|
||||
OPCODE(WriteMemory32, T::Void, T::U32, T::U32 )
|
||||
OPCODE(WriteMemory64, T::Void, T::U32, T::U64 )
|
||||
OPCODE(ExclusiveWriteMemory8, T::U32, T::U32, T::U8 )
|
||||
OPCODE(ExclusiveWriteMemory16, T::U32, T::U32, T::U16 )
|
||||
OPCODE(ExclusiveWriteMemory32, T::U32, T::U32, T::U32 )
|
||||
OPCODE(ExclusiveWriteMemory64, T::U32, T::U32, T::U32, T::U32 )
|
||||
|
|
|
|||
162
src/frontend/translate/translate_arm/synchronization.cpp
Normal file
162
src/frontend/translate/translate_arm/synchronization.cpp
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* This software may be used and distributed according to the terms of the GNU
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "translate_arm.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Arm {
|
||||
|
||||
bool ArmTranslatorVisitor::arm_CLREX() {
|
||||
// CLREX
|
||||
ir.ClearExlcusive();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_LDREX(Cond cond, Reg n, Reg d) {
|
||||
if (d == Reg::PC || n == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
// LDREX <Rd>, [<Rn>]
|
||||
if (ConditionPassed(cond)) {
|
||||
auto address = ir.GetRegister(n);
|
||||
ir.SetExclusive(address, 4);
|
||||
ir.SetRegister(d, ir.ReadMemory32(address));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_LDREXB(Cond cond, Reg n, Reg d) {
|
||||
if (d == Reg::PC || n == Reg::PC)
|
||||
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)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_LDREXD(Cond cond, Reg n, Reg d) {
|
||||
if (d == Reg::LR || d == Reg::PC || n == Reg::PC)
|
||||
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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_LDREXH(Cond cond, Reg n, Reg d) {
|
||||
if (d == Reg::PC || n == Reg::PC)
|
||||
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)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_STREX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC)
|
||||
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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_STREXB(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC)
|
||||
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);
|
||||
}
|
||||
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<size_t>(m) % 2 == 1)
|
||||
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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_STREXH(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC)
|
||||
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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
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));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Arm
|
||||
} // namespace Dynarmic
|
||||
|
|
@ -304,17 +304,17 @@ struct ArmTranslatorVisitor final {
|
|||
bool arm_QDSUB(Cond cond, Reg n, Reg d, Reg m) { return InterpretThisInstruction(); }
|
||||
|
||||
// Synchronization Primitive instructions
|
||||
bool arm_CLREX() { return InterpretThisInstruction(); }
|
||||
bool arm_LDREX(Cond cond, Reg n, Reg d) { return InterpretThisInstruction(); }
|
||||
bool arm_LDREXB(Cond cond, Reg n, Reg d) { return InterpretThisInstruction(); }
|
||||
bool arm_LDREXD(Cond cond, Reg n, Reg d) { return InterpretThisInstruction(); }
|
||||
bool arm_LDREXH(Cond cond, Reg n, Reg d) { return InterpretThisInstruction(); }
|
||||
bool arm_STREX(Cond cond, Reg n, Reg d, Reg m) { return InterpretThisInstruction(); }
|
||||
bool arm_STREXB(Cond cond, Reg n, Reg d, Reg m) { return InterpretThisInstruction(); }
|
||||
bool arm_STREXD(Cond cond, Reg n, Reg d, Reg m) { return InterpretThisInstruction(); }
|
||||
bool arm_STREXH(Cond cond, Reg n, Reg d, Reg m) { return InterpretThisInstruction(); }
|
||||
bool arm_SWP(Cond cond, Reg n, Reg d, Reg m) { return InterpretThisInstruction(); }
|
||||
bool arm_SWPB(Cond cond, Reg n, Reg d, Reg m) { return InterpretThisInstruction(); }
|
||||
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);
|
||||
|
||||
// Status register access instructions
|
||||
bool arm_CPS() { return InterpretThisInstruction(); }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue