A64: Implement logical

This commit is contained in:
MerryMage 2018-01-07 12:52:12 +00:00
parent 5a1d88c5dc
commit 0641445e51
13 changed files with 499 additions and 26 deletions

View file

@ -59,6 +59,7 @@ add_library(dynarmic
frontend/A64/location_descriptor.cpp
frontend/A64/location_descriptor.h
frontend/A64/translate/impl/data_processing_addsub.cpp
frontend/A64/translate/impl/data_processing_logical.cpp
frontend/A64/translate/impl/data_processing_pcrel.cpp
frontend/A64/translate/impl/impl.cpp
frontend/A64/translate/impl/impl.h

View file

@ -150,6 +150,7 @@ private:
// JIT Compile
IR::Block ir_block = A64::Translate(A64::LocationDescriptor{current_location}, [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); });
Optimization::DeadCodeElimination(ir_block);
// printf("%s\n", IR::DumpBlock(ir_block).c_str());
Optimization::VerificationPass(ir_block);
return emitter.Emit(ir_block).entrypoint;
}

View file

@ -132,8 +132,31 @@ void EmitX64<JST>::EmitGetGEFromOp(EmitContext&, IR::Inst*) {
}
template <typename JST>
void EmitX64<JST>::EmitGetNZCVFromOp(EmitContext&, IR::Inst*) {
ASSERT_MSG(false, "should never happen");
void EmitX64<JST>::EmitGetNZCVFromOp(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const size_t bitsize = [&]{
switch (args[0].GetType()) {
case IR::Type::U8:
return 8;
case IR::Type::U16:
return 16;
case IR::Type::U32:
return 32;
case IR::Type::U64:
return 64;
default:
ASSERT_MSG(false, "Unreachable");
return 0;
}
}();
Xbyak::Reg64 nzcv = ctx.reg_alloc.ScratchGpr({HostLoc::RAX});
Xbyak::Reg value = ctx.reg_alloc.UseGpr(args[0]).changeBit(bitsize);
code->cmp(value, 0);
code->lahf();
code->seto(code->al);
ctx.reg_alloc.DefineValue(inst, nzcv);
}
template <typename JST>
@ -933,7 +956,7 @@ void EmitX64<JST>::EmitMul64(EmitContext& ctx, IR::Inst* inst) {
}
template <typename JST>
void EmitX64<JST>::EmitAnd(EmitContext& ctx, IR::Inst* inst) {
void EmitX64<JST>::EmitAnd32(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg32 result = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
@ -953,7 +976,27 @@ void EmitX64<JST>::EmitAnd(EmitContext& ctx, IR::Inst* inst) {
}
template <typename JST>
void EmitX64<JST>::EmitEor(EmitContext& ctx, IR::Inst* inst) {
void EmitX64<JST>::EmitAnd64(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(args[0]);
if (args[1].FitsInImmediateU32()) {
u32 op_arg = args[1].GetImmediateU32();
code->and_(result, op_arg);
} else {
OpArg op_arg = ctx.reg_alloc.UseOpArg(args[1]);
op_arg.setBit(64);
code->and_(result, *op_arg);
}
ctx.reg_alloc.DefineValue(inst, result);
}
template <typename JST>
void EmitX64<JST>::EmitEor32(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg32 result = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
@ -973,7 +1016,27 @@ void EmitX64<JST>::EmitEor(EmitContext& ctx, IR::Inst* inst) {
}
template <typename JST>
void EmitX64<JST>::EmitOr(EmitContext& ctx, IR::Inst* inst) {
void EmitX64<JST>::EmitEor64(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(args[0]);
if (args[1].FitsInImmediateU32()) {
u32 op_arg = args[1].GetImmediateU32();
code->xor_(result, op_arg);
} else {
OpArg op_arg = ctx.reg_alloc.UseOpArg(args[1]);
op_arg.setBit(64);
code->xor_(result, *op_arg);
}
ctx.reg_alloc.DefineValue(inst, result);
}
template <typename JST>
void EmitX64<JST>::EmitOr32(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg32 result = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
@ -993,7 +1056,27 @@ void EmitX64<JST>::EmitOr(EmitContext& ctx, IR::Inst* inst) {
}
template <typename JST>
void EmitX64<JST>::EmitNot(EmitContext& ctx, IR::Inst* inst) {
void EmitX64<JST>::EmitOr64(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(args[0]);
if (args[1].FitsInImmediateU32()) {
u32 op_arg = args[1].GetImmediateU32();
code->or_(result, op_arg);
} else {
OpArg op_arg = ctx.reg_alloc.UseOpArg(args[1]);
op_arg.setBit(64);
code->or_(result, *op_arg);
}
ctx.reg_alloc.DefineValue(inst, result);
}
template <typename JST>
void EmitX64<JST>::EmitNot32(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg32 result;
@ -1007,6 +1090,21 @@ void EmitX64<JST>::EmitNot(EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(inst, result);
}
template <typename JST>
void EmitX64<JST>::EmitNot64(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg64 result;
if (args[0].IsImmediate()) {
result = ctx.reg_alloc.ScratchGpr();
code->mov(result, ~args[0].GetImmediateU64());
} else {
result = ctx.reg_alloc.UseScratchGpr(args[0]);
code->not_(result);
}
ctx.reg_alloc.DefineValue(inst, result);
}
template <typename JST>
void EmitX64<JST>::EmitSignExtendByteToWord(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);

View file

@ -9,6 +9,7 @@
#include <bitset>
#include <climits>
#include <cstddef>
#include <type_traits>
#include "common/assert.h"
@ -86,5 +87,37 @@ inline size_t BitCount(Integral value) {
return std::bitset<BitSize<Integral>()>(value).count();
}
template <typename T>
inline int HighestSetBit(T value) {
auto x = static_cast<std::make_unsigned_t<T>>(value);
int result = -1;
while (x != 0) {
x >>= 1;
result++;
}
return result;
}
template <typename T>
inline T Ones(size_t count) {
ASSERT_MSG(count <= BitSize<T>(), "count larger than bitsize of T");
return ~(~static_cast<T>(0) << count);
}
template <typename T>
inline T Replicate(T value, size_t element_size) {
ASSERT_MSG(BitSize<T>() % element_size == 0, "bitsize of T not divisible by element_size");
if (element_size == BitSize<T>())
return value;
return Replicate(value | (value << element_size), element_size * 2);
}
template <typename T>
inline T RotateRight(T value, size_t amount) {
amount %= BitSize<T>();
auto x = static_cast<std::make_unsigned_t<T>>(value);
return static_cast<T>((x >> amount) | (x << (BitSize<T>() - amount)));
}
} // namespace Common
} // namespace Dynarmic

View file

@ -40,10 +40,10 @@ std::vector<Matcher<V>> GetDecodeTable() {
INST(&V::SUBS_imm, "SUBS (immediate)", "z1110001ssiiiiiiiiiiiinnnnnddddd"),
// Data processing - Immediate - Logical
//INST(&V::AND_imm, "AND (immediate)", "z00100100Nrrrrrrssssssnnnnnddddd"),
//INST(&V::ORR_imm, "ORR (immediate)", "z01100100Nrrrrrrssssssnnnnnddddd"),
//INST(&V::EOR_imm, "EOR (immediate)", "z10100100Nrrrrrrssssssnnnnnddddd"),
//INST(&V::ANDS_imm, "ANDS (immediate)", "z11100100Nrrrrrrssssssnnnnnddddd"),
INST(&V::AND_imm, "AND (immediate)", "z00100100Nrrrrrrssssssnnnnnddddd"),
INST(&V::ORR_imm, "ORR (immediate)", "z01100100Nrrrrrrssssssnnnnnddddd"),
INST(&V::EOR_imm, "EOR (immediate)", "z10100100Nrrrrrrssssssnnnnnddddd"),
INST(&V::ANDS_imm, "ANDS (immediate)", "z11100100Nrrrrrrssssssnnnnnddddd"),
// Data processing - Immediate - Move Wide
//INST(&V::MOVN, "MOVN", "z00100101ssiiiiiiiiiiiiiiiiddddd"),
@ -363,14 +363,14 @@ std::vector<Matcher<V>> GetDecodeTable() {
//INST(&V::AUTDB, "AUTDB, AUTDZB", "110110101100000100Z111nnnnnddddd"),
// Data Processing - Register - Logical (shifted register)
//INST(&V::AND_shift, "AND (shifted register)", "z0001010ss0mmmmmiiiiiinnnnnddddd"),
//INST(&V::BIC_shift, "BIC (shifted register)", "z0001010ss1mmmmmiiiiiinnnnnddddd"),
//INST(&V::ORR_shift, "ORR (shifted register)", "z0101010ss0mmmmmiiiiiinnnnnddddd"),
//INST(&V::ORN_shift, "ORN (shifted register)", "z0101010ss1mmmmmiiiiiinnnnnddddd"),
//INST(&V::EOR_shift, "EOR (shifted register)", "z1001010ss0mmmmmiiiiiinnnnnddddd"),
//INST(&V::EON, "EON (shifted register)", "z1001010ss1mmmmmiiiiiinnnnnddddd"),
//INST(&V::ANDS_shift, "ANDS (shifted register)", "z1101010ss0mmmmmiiiiiinnnnnddddd"),
//INST(&V::BICS, "BICS (shifted register)", "z1101010ss1mmmmmiiiiiinnnnnddddd"),
INST(&V::AND_shift, "AND (shifted register)", "z0001010ss0mmmmmiiiiiinnnnnddddd"),
INST(&V::BIC_shift, "BIC (shifted register)", "z0001010ss1mmmmmiiiiiinnnnnddddd"),
INST(&V::ORR_shift, "ORR (shifted register)", "z0101010ss0mmmmmiiiiiinnnnnddddd"),
INST(&V::ORN_shift, "ORN (shifted register)", "z0101010ss1mmmmmiiiiiinnnnnddddd"),
INST(&V::EOR_shift, "EOR (shifted register)", "z1001010ss0mmmmmiiiiiinnnnnddddd"),
INST(&V::EON, "EON (shifted register)", "z1001010ss1mmmmmiiiiiinnnnnddddd"),
INST(&V::ANDS_shift, "ANDS (shifted register)", "z1101010ss0mmmmmiiiiiinnnnnddddd"),
INST(&V::BICS, "BICS (shifted register)", "z1101010ss1mmmmmiiiiiinnnnnddddd"),
// Data Processing - Register - Add/Sub (shifted register)
INST(&V::ADD_shift, "ADD (shifted register)", "z0001011ss0mmmmmiiiiiinnnnnddddd"),

View file

@ -0,0 +1,216 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2018 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 "frontend/A64/translate/impl/impl.h"
namespace Dynarmic {
namespace A64 {
bool TranslatorVisitor::AND_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && N) return ReservedValue();
u64 imm;
if (auto masks = DecodeBitMasks(N, imms, immr, true)) {
imm = masks->wmask;
} else {
return ReservedValue();
}
auto operand1 = X(datasize, Rn);
auto result = ir.And(operand1, I(datasize, imm));
if (Rd == Reg::SP) {
SP(datasize, result);
} else {
X(datasize, Rd, result);
}
return true;
}
bool TranslatorVisitor::ORR_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && N) return ReservedValue();
u64 imm;
if (auto masks = DecodeBitMasks(N, imms, immr, true)) {
imm = masks->wmask;
} else {
return ReservedValue();
}
auto operand1 = X(datasize, Rn);
auto result = ir.Or(operand1, I(datasize, imm));
if (Rd == Reg::SP) {
SP(datasize, result);
} else {
X(datasize, Rd, result);
}
return true;
}
bool TranslatorVisitor::EOR_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && N) return ReservedValue();
u64 imm;
if (auto masks = DecodeBitMasks(N, imms, immr, true)) {
imm = masks->wmask;
} else {
return ReservedValue();
}
auto operand1 = X(datasize, Rn);
auto result = ir.Eor(operand1, I(datasize, imm));
if (Rd == Reg::SP) {
SP(datasize, result);
} else {
X(datasize, Rd, result);
}
return true;
}
bool TranslatorVisitor::ANDS_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && N) return ReservedValue();
u64 imm;
if (auto masks = DecodeBitMasks(N, imms, immr, true)) {
imm = masks->wmask;
} else {
return ReservedValue();
}
auto operand1 = X(datasize, Rn);
auto result = ir.And(operand1, I(datasize, imm));
ir.SetNZCV(ir.NZCVFrom(result));
X(datasize, Rd, result);
return true;
}
bool TranslatorVisitor::AND_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && imm6.Bit<5>()) return ReservedValue();
u8 shift_amount = imm6.ZeroExtend<u8>();
auto operand1 = X(datasize, Rn);
auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
auto result = ir.And(operand1, operand2);
X(datasize, Rd, result);
return true;
}
bool TranslatorVisitor::BIC_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && imm6.Bit<5>()) return ReservedValue();
u8 shift_amount = imm6.ZeroExtend<u8>();
auto operand1 = X(datasize, Rn);
auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
operand2 = ir.Not(operand2);
auto result = ir.And(operand1, operand2);
X(datasize, Rd, result);
return true;
}
bool TranslatorVisitor::ORR_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && imm6.Bit<5>()) return ReservedValue();
u8 shift_amount = imm6.ZeroExtend<u8>();
auto operand1 = X(datasize, Rn);
auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
auto result = ir.Or(operand1, operand2);
X(datasize, Rd, result);
return true;
}
bool TranslatorVisitor::ORN_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && imm6.Bit<5>()) return ReservedValue();
u8 shift_amount = imm6.ZeroExtend<u8>();
auto operand1 = X(datasize, Rn);
auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
operand2 = ir.Not(operand2);
auto result = ir.Or(operand1, operand2);
X(datasize, Rd, result);
return true;
}
bool TranslatorVisitor::EOR_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && imm6.Bit<5>()) return ReservedValue();
u8 shift_amount = imm6.ZeroExtend<u8>();
auto operand1 = X(datasize, Rn);
auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
auto result = ir.Eor(operand1, operand2);
X(datasize, Rd, result);
return true;
}
bool TranslatorVisitor::EON(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && imm6.Bit<5>()) return ReservedValue();
u8 shift_amount = imm6.ZeroExtend<u8>();
auto operand1 = X(datasize, Rn);
auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
operand2 = ir.Not(operand2);
auto result = ir.Eor(operand1, operand2);
X(datasize, Rd, result);
return true;
}
bool TranslatorVisitor::ANDS_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && imm6.Bit<5>()) return ReservedValue();
u8 shift_amount = imm6.ZeroExtend<u8>();
auto operand1 = X(datasize, Rn);
auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
auto result = ir.And(operand1, operand2);
ir.SetNZCV(ir.NZCVFrom(result));
X(datasize, Rd, result);
return true;
}
bool TranslatorVisitor::BICS(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (!sf && imm6.Bit<5>()) return ReservedValue();
u8 shift_amount = imm6.ZeroExtend<u8>();
auto operand1 = X(datasize, Rn);
auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
operand2 = ir.Not(operand2);
auto result = ir.And(operand1, operand2);
ir.SetNZCV(ir.NZCVFrom(result));
X(datasize, Rd, result);
return true;
}
} // namespace A64
} // namespace Dynarmic

View file

@ -4,6 +4,7 @@
* General Public License version 2 or any later version.
*/
#include "common/bit_util.h"
#include "frontend/ir/terminal.h"
#include "frontend/A64/translate/impl/impl.h"
@ -25,6 +26,29 @@ bool TranslatorVisitor::ReservedValue() {
return false;
}
boost::optional<TranslatorVisitor::BitMasks> TranslatorVisitor::DecodeBitMasks(bool immN, Imm<6> imms, Imm<6> immr, bool immediate) {
int len = Common::HighestSetBit((immN ? 1 << 6 : 0) | (imms.ZeroExtend() ^ 0b111111));
if (len < 1)
return boost::none;
size_t levels = Common::Ones<size_t>(len);
if (immediate && (imms.ZeroExtend() & levels) == levels)
return boost::none;
s32 S = s32(imms.ZeroExtend() & levels);
s32 R = s32(immr.ZeroExtend() & levels);
u64 d = u64(S - R) & levels;
size_t esize = 1 << len;
u64 welem = Common::Ones<u64>(S + 1);
u64 telem = Common::Ones<u64>(d + 1);
u64 wmask = Common::RotateRight(Common::Replicate(welem, esize), R);
u64 tmask = Common::Replicate(telem, esize);
return BitMasks{wmask, tmask};
}
IR::U32U64 TranslatorVisitor::I(size_t bitsize, u64 value) {
switch (bitsize) {
case 32:

View file

@ -6,6 +6,8 @@
#pragma once
#include <boost/optional.hpp>
#include "frontend/A64/imm.h"
#include "frontend/A64/ir_emitter.h"
#include "frontend/A64/location_descriptor.h"
@ -25,6 +27,12 @@ struct TranslatorVisitor final {
bool UnpredictableInstruction();
bool ReservedValue();
struct BitMasks {
u64 wmask, tmask;
};
boost::optional<BitMasks> DecodeBitMasks(bool N, Imm<6> immr, Imm<6> imms, bool immediate);
IR::U32U64 I(size_t bitsize, u64 value);
IR::U32U64 X(size_t bitsize, Reg reg);
void X(size_t bitsize, Reg reg, IR::U32U64 value);

View file

@ -221,19 +221,54 @@ U64 IREmitter::Mul(const U64& a, const U64& b) {
}
U32 IREmitter::And(const U32& a, const U32& b) {
return Inst<U32>(Opcode::And, a, b);
return Inst<U32>(Opcode::And32, a, b);
}
U32U64 IREmitter::And(const U32U64& a, const U32U64& b) {
ASSERT(a.GetType() == b.GetType());
if (a.GetType() == Type::U32) {
return Inst<U32>(Opcode::And32, a, b);
} else {
return Inst<U64>(Opcode::And64, a, b);
}
}
U32 IREmitter::Eor(const U32& a, const U32& b) {
return Inst<U32>(Opcode::Eor, a, b);
return Inst<U32>(Opcode::Eor32, a, b);
}
U32U64 IREmitter::Eor(const U32U64& a, const U32U64& b) {
ASSERT(a.GetType() == b.GetType());
if (a.GetType() == Type::U32) {
return Inst<U32>(Opcode::Eor32, a, b);
} else {
return Inst<U64>(Opcode::Eor64, a, b);
}
}
U32 IREmitter::Or(const U32& a, const U32& b) {
return Inst<U32>(Opcode::Or, a, b);
return Inst<U32>(Opcode::Or32, a, b);
}
U32U64 IREmitter::Or(const U32U64& a, const U32U64& b) {
ASSERT(a.GetType() == b.GetType());
if (a.GetType() == Type::U32) {
return Inst<U32>(Opcode::Or32, a, b);
} else {
return Inst<U64>(Opcode::Or64, a, b);
}
}
U32 IREmitter::Not(const U32& a) {
return Inst<U32>(Opcode::Not, a);
return Inst<U32>(Opcode::Not32, a);
}
U32U64 IREmitter::Not(const U32U64& a) {
if (a.GetType() == Type::U32) {
return Inst<U32>(Opcode::Not32, a);
} else {
return Inst<U64>(Opcode::Not64, a);
}
}
U64 IREmitter::SignExtendToLong(const UAny& a) {

View file

@ -108,9 +108,13 @@ public:
U32 Mul(const U32& a, const U32& b);
U64 Mul(const U64& a, const U64& b);
U32 And(const U32& a, const U32& b);
U32U64 And(const U32U64& a, const U32U64& b);
U32 Eor(const U32& a, const U32& b);
U32U64 Eor(const U32U64& a, const U32U64& b);
U32 Or(const U32& a, const U32& b);
U32U64 Or(const U32U64& a, const U32U64& b);
U32 Not(const U32& a);
U32U64 Not(const U32U64& a);
U32 SignExtendToWord(const UAny& a);
U64 SignExtendToLong(const UAny& a);
U32 SignExtendByteToWord(const U8& a);

View file

@ -273,6 +273,14 @@ bool Inst::MayGetNZCVFromOp() const {
case Opcode::Add64:
case Opcode::Sub32:
case Opcode::Sub64:
case Opcode::And32:
case Opcode::And64:
case Opcode::Eor32:
case Opcode::Eor64:
case Opcode::Or32:
case Opcode::Or64:
case Opcode::Not32:
case Opcode::Not64:
return true;
default:

View file

@ -77,10 +77,14 @@ OPCODE(Sub32, T::U32, T::U32, T::U32,
OPCODE(Sub64, T::U64, T::U64, T::U64, T::U1 )
OPCODE(Mul32, T::U32, T::U32, T::U32 )
OPCODE(Mul64, T::U64, T::U64, T::U64 )
OPCODE(And, T::U32, T::U32, T::U32 )
OPCODE(Eor, T::U32, T::U32, T::U32 )
OPCODE(Or, T::U32, T::U32, T::U32 )
OPCODE(Not, T::U32, T::U32 )
OPCODE(And32, T::U32, T::U32, T::U32 )
OPCODE(And64, T::U64, T::U64, T::U64 )
OPCODE(Eor32, T::U32, T::U32, T::U32 )
OPCODE(Eor64, T::U64, T::U64, T::U64 )
OPCODE(Or32, T::U32, T::U32, T::U32 )
OPCODE(Or64, T::U64, T::U64, T::U64 )
OPCODE(Not32, T::U32, T::U32 )
OPCODE(Not64, T::U64, T::U64 )
OPCODE(SignExtendByteToWord, T::U32, T::U8 )
OPCODE(SignExtendHalfToWord, T::U32, T::U16 )
OPCODE(SignExtendByteToLong, T::U64, T::U8 )

View file

@ -72,3 +72,44 @@ TEST_CASE("A64: ADD", "[a64]") {
REQUIRE(jit.GetRegister(2) == 2);
REQUIRE(jit.GetPC() == 4);
}
TEST_CASE("A64: AND", "[a64]") {
TestEnv env;
Dynarmic::A64::Jit jit{Dynarmic::A64::UserConfig{&env}};
env.code_mem[0] = 0x8a020020; // AND X0, X1, X2
env.code_mem[1] = 0x14000000; // B .
jit.SetRegister(0, 0);
jit.SetRegister(1, 1);
jit.SetRegister(2, 3);
jit.SetPC(0);
env.ticks_left = 2;
jit.Run();
REQUIRE(jit.GetRegister(0) == 1);
REQUIRE(jit.GetRegister(1) == 1);
REQUIRE(jit.GetRegister(2) == 3);
REQUIRE(jit.GetPC() == 4);
}
TEST_CASE("A64: Bitmasks", "[a64]") {
TestEnv env;
Dynarmic::A64::Jit jit{Dynarmic::A64::UserConfig{&env}};
env.code_mem[0] = 0x3200c3e0; // ORR W0, WZR, #0x01010101
env.code_mem[1] = 0x320c8fe1; // ORR W1, WZR, #0x00F000F0
env.code_mem[2] = 0x320003e2; // ORR W2, WZR, #1
env.code_mem[3] = 0x14000000; // B .
jit.SetPC(0);
env.ticks_left = 4;
jit.Run();
REQUIRE(jit.GetRegister(0) == 0x01010101);
REQUIRE(jit.GetRegister(1) == 0x00F000F0);
REQUIRE(jit.GetRegister(2) == 1);
REQUIRE(jit.GetPC() == 12);
}