mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-01-05 22:18:16 +01:00
A64: Implement logical
This commit is contained in:
parent
5a1d88c5dc
commit
0641445e51
13 changed files with 499 additions and 26 deletions
|
|
@ -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"),
|
||||
|
|
|
|||
216
src/frontend/A64/translate/impl/data_processing_logical.cpp
Normal file
216
src/frontend/A64/translate/impl/data_processing_logical.cpp
Normal 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
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue