mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-03-11 01:52:58 +00:00
A64: Implement compare and branch
This commit is contained in:
@@ -127,6 +127,10 @@ static std::string TerminalToString(const Terminal& terminal_variant) {
|
||||
return fmt::format("If{{{}, {}, {}}}", A32::CondToString(terminal.if_), TerminalToString(terminal.then_), TerminalToString(terminal.else_));
|
||||
}
|
||||
case 7: {
|
||||
auto terminal = boost::get<IR::Term::CheckBit>(terminal_variant);
|
||||
return fmt::format("CheckBit{{{}, {}}}", TerminalToString(terminal.then_), TerminalToString(terminal.else_));
|
||||
}
|
||||
case 8: {
|
||||
auto terminal = boost::get<IR::Term::CheckHalt>(terminal_variant);
|
||||
return fmt::format("CheckHalt{{{}}}", TerminalToString(terminal.else_));
|
||||
}
|
||||
|
||||
@@ -68,13 +68,29 @@ U1 IREmitter::MostSignificantBit(const U32& value) {
|
||||
}
|
||||
|
||||
U1 IREmitter::IsZero(const U32& value) {
|
||||
return Inst<U1>(Opcode::IsZero, value);
|
||||
return Inst<U1>(Opcode::IsZero32, value);
|
||||
}
|
||||
|
||||
U1 IREmitter::IsZero64(const U64& value) {
|
||||
U1 IREmitter::IsZero(const U64& value) {
|
||||
return Inst<U1>(Opcode::IsZero64, value);
|
||||
}
|
||||
|
||||
U1 IREmitter::IsZero(const U32U64& value) {
|
||||
if (value.GetType() == Type::U32) {
|
||||
return Inst<U1>(Opcode::IsZero32, value);
|
||||
} else {
|
||||
return Inst<U1>(Opcode::IsZero64, value);
|
||||
}
|
||||
}
|
||||
|
||||
U1 IREmitter::TestBit(const U32U64& value, const U8& bit) {
|
||||
if (value.GetType() == Type::U32) {
|
||||
return Inst<U1>(Opcode::TestBit, IndeterminateExtendToLong(value), bit);
|
||||
} else {
|
||||
return Inst<U1>(Opcode::TestBit, value, bit);
|
||||
}
|
||||
}
|
||||
|
||||
NZCV IREmitter::NZCVFrom(const Value& value) {
|
||||
return Inst<NZCV>(Opcode::GetNZCVFromOp, value);
|
||||
}
|
||||
@@ -359,6 +375,16 @@ U32 IREmitter::ZeroExtendByteToWord(const U8& a) {
|
||||
return Inst<U32>(Opcode::ZeroExtendByteToWord, a);
|
||||
}
|
||||
|
||||
U32 IREmitter::IndeterminateExtendToWord(const UAny& a) {
|
||||
// TODO: Implement properly
|
||||
return ZeroExtendToWord(a);
|
||||
}
|
||||
|
||||
U64 IREmitter::IndeterminateExtendToLong(const UAny& a) {
|
||||
// TODO: Implement properly
|
||||
return ZeroExtendToLong(a);
|
||||
}
|
||||
|
||||
U32 IREmitter::ByteReverseWord(const U32& a) {
|
||||
return Inst<U32>(Opcode::ByteReverseWord, a);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,9 @@ public:
|
||||
U8 LeastSignificantByte(U32U64 value);
|
||||
U1 MostSignificantBit(const U32& value);
|
||||
U1 IsZero(const U32& value);
|
||||
U1 IsZero64(const U64& value);
|
||||
U1 IsZero(const U64& value);
|
||||
U1 IsZero(const U32U64& value);
|
||||
U1 TestBit(const U32U64& value, const U8& bit);
|
||||
|
||||
// This pseudo-instruction may only be added to instructions that support it.
|
||||
NZCV NZCVFrom(const Value& value);
|
||||
@@ -125,6 +127,8 @@ public:
|
||||
U32 ZeroExtendByteToWord(const U8& a);
|
||||
U32 ZeroExtendHalfToWord(const U16& a);
|
||||
U64 ZeroExtendWordToLong(const U32& a);
|
||||
U32 IndeterminateExtendToWord(const UAny& a);
|
||||
U64 IndeterminateExtendToLong(const UAny& a);
|
||||
U32 ByteReverseWord(const U32& a);
|
||||
U16 ByteReverseHalf(const U16& a);
|
||||
U64 ByteReverseDual(const U64& a);
|
||||
|
||||
@@ -246,13 +246,14 @@ bool Inst::IsCoprocessorInstruction() const {
|
||||
}
|
||||
|
||||
bool Inst::MayHaveSideEffects() const {
|
||||
return op == Opcode::PushRSB ||
|
||||
CausesCPUException() ||
|
||||
WritesToCoreRegister() ||
|
||||
WritesToCPSR() ||
|
||||
WritesToFPSCR() ||
|
||||
AltersExclusiveState() ||
|
||||
IsMemoryWrite() ||
|
||||
return op == Opcode::PushRSB ||
|
||||
op == Opcode::A64SetCheckBit ||
|
||||
CausesCPUException() ||
|
||||
WritesToCoreRegister() ||
|
||||
WritesToCPSR() ||
|
||||
WritesToFPSCR() ||
|
||||
AltersExclusiveState() ||
|
||||
IsMemoryWrite() ||
|
||||
IsCoprocessorInstruction();
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ A32OPC(GetFpscrNZCV, T::U32,
|
||||
A32OPC(SetFpscrNZCV, T::Void, T::U32, )
|
||||
|
||||
// A64 Context getters/setters
|
||||
A64OPC(SetCheckBit, T::Void, T::U1 )
|
||||
A64OPC(GetCFlag, T::U1, )
|
||||
A64OPC(SetNZCV, T::Void, T::NZCVFlags )
|
||||
A64OPC(GetW, T::U32, T::A64Reg )
|
||||
@@ -61,8 +62,9 @@ OPCODE(MostSignificantWord, T::U32, T::U64
|
||||
OPCODE(LeastSignificantHalf, T::U16, T::U32 )
|
||||
OPCODE(LeastSignificantByte, T::U8, T::U32 )
|
||||
OPCODE(MostSignificantBit, T::U1, T::U32 )
|
||||
OPCODE(IsZero, T::U1, T::U32 )
|
||||
OPCODE(IsZero32, T::U1, T::U32 )
|
||||
OPCODE(IsZero64, T::U1, T::U64 )
|
||||
OPCODE(TestBit, T::U1, T::U64, T::U8 )
|
||||
OPCODE(LogicalShiftLeft32, T::U32, T::U32, T::U8, T::U1 )
|
||||
OPCODE(LogicalShiftLeft64, T::U64, T::U64, T::U8 )
|
||||
OPCODE(LogicalShiftRight32, T::U32, T::U32, T::U8, T::U1 )
|
||||
|
||||
@@ -66,6 +66,7 @@ struct LinkBlockFast {
|
||||
struct PopRSBHint {};
|
||||
|
||||
struct If;
|
||||
struct CheckBit;
|
||||
struct CheckHalt;
|
||||
/// A Terminal is the terminal instruction in a MicroBlock.
|
||||
using Terminal = boost::variant<
|
||||
@@ -76,6 +77,7 @@ using Terminal = boost::variant<
|
||||
LinkBlockFast,
|
||||
PopRSBHint,
|
||||
boost::recursive_wrapper<If>,
|
||||
boost::recursive_wrapper<CheckBit>,
|
||||
boost::recursive_wrapper<CheckHalt>
|
||||
>;
|
||||
|
||||
@@ -90,6 +92,17 @@ struct If {
|
||||
Terminal else_;
|
||||
};
|
||||
|
||||
/**
|
||||
* This terminal instruction conditionally executes one terminal or another depending
|
||||
* on the run-time state of the check bit.
|
||||
* then_ is executed if the check bit is non-zero, otherwise else_ is executed.
|
||||
*/
|
||||
struct CheckBit {
|
||||
CheckBit(Terminal then_, Terminal else_) : then_(then_), else_(else_) {}
|
||||
Terminal then_;
|
||||
Terminal else_;
|
||||
};
|
||||
|
||||
/**
|
||||
* This terminal instruction checks if a halt was requested. If it wasn't, else_ is
|
||||
* executed.
|
||||
|
||||
Reference in New Issue
Block a user