A64: Implement ADD_shifted

This commit is contained in:
MerryMage 2018-01-07 00:11:57 +00:00
parent d1eb757f93
commit d1cef6ffb0
21 changed files with 451 additions and 75 deletions

View file

@ -52,9 +52,14 @@ add_library(dynarmic
frontend/A32/types.cpp frontend/A32/types.cpp
frontend/A32/types.h frontend/A32/types.h
frontend/A64/decoder/a64.h frontend/A64/decoder/a64.h
frontend/A64/FPCR.h
frontend/A64/imm.h frontend/A64/imm.h
frontend/A64/ir_emitter.cpp
frontend/A64/ir_emitter.h
frontend/A64/location_descriptor.cpp frontend/A64/location_descriptor.cpp
frontend/A64/location_descriptor.h frontend/A64/location_descriptor.h
frontend/A64/translate/impl/data_processing_addsub.cpp
frontend/A64/translate/impl/impl.cpp
frontend/A64/translate/impl/impl.h frontend/A64/translate/impl/impl.h
frontend/A64/translate/translate.cpp frontend/A64/translate/translate.cpp
frontend/A64/translate/translate.h frontend/A64/translate/translate.h

View file

@ -64,9 +64,11 @@ protected:
// Microinstruction emitters // Microinstruction emitters
#define OPCODE(...) #define OPCODE(...)
#define A32OPC(name, type, ...) void EmitA32##name(A32EmitContext& ctx, IR::Inst* inst); #define A32OPC(name, type, ...) void EmitA32##name(A32EmitContext& ctx, IR::Inst* inst);
#define A64OPC(...)
#include "frontend/ir/opcodes.inc" #include "frontend/ir/opcodes.inc"
#undef OPCODE #undef OPCODE
#undef A32OPC #undef A32OPC
#undef A64OPC
// Terminal instruction emitters // Terminal instruction emitters
void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) override; void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) override;

View file

@ -115,11 +115,56 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) {
return block_desc; return block_desc;
} }
void A64EmitX64::EmitA64GetW(A64EmitContext& ctx, IR::Inst* inst) {
A64::Reg reg = inst->GetArg(0).GetA64RegRef();
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
code->mov(result, dword[r15 + offsetof(A64JitState, reg) + sizeof(u64) * static_cast<size_t>(reg)]);
ctx.reg_alloc.DefineValue(inst, result);
}
void A64EmitX64::EmitA64GetX(A64EmitContext& ctx, IR::Inst* inst) {
A64::Reg reg = inst->GetArg(0).GetA64RegRef();
Xbyak::Reg64 result = ctx.reg_alloc.ScratchGpr();
code->mov(result, qword[r15 + offsetof(A64JitState, reg) + sizeof(u64) * static_cast<size_t>(reg)]);
ctx.reg_alloc.DefineValue(inst, result);
}
void A64EmitX64::EmitA64SetW(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
A64::Reg reg = inst->GetArg(0).GetA64RegRef();
auto addr = dword[r15 + offsetof(A64JitState, reg) + sizeof(u64) * static_cast<size_t>(reg)];
if (args[1].IsImmediate()) {
code->mov(addr, args[1].GetImmediateU32());
} else if (args[1].IsInXmm()) {
Xbyak::Xmm to_store = ctx.reg_alloc.UseXmm(args[1]);
code->movd(addr, to_store);
} else {
Xbyak::Reg32 to_store = ctx.reg_alloc.UseGpr(args[1]).cvt32();
code->mov(addr, to_store);
}
}
void A64EmitX64::EmitA64SetX(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
A64::Reg reg = inst->GetArg(0).GetA64RegRef();
auto addr = qword[r15 + offsetof(A64JitState, reg) + sizeof(u64) * static_cast<size_t>(reg)];
if (args[1].IsImmediate()) {
code->mov(addr, args[1].GetImmediateU64());
} else if (args[1].IsInXmm()) {
Xbyak::Xmm to_store = ctx.reg_alloc.UseXmm(args[1]);
code->movq(addr, to_store);
} else {
Xbyak::Reg64 to_store = ctx.reg_alloc.UseGpr(args[1]);
code->mov(addr, to_store);
}
}
void A64EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor) { void A64EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor) {
code->mov(code->ABI_PARAM1.cvt32(), A64::LocationDescriptor{terminal.next}.PC()); code->mov(code->ABI_PARAM1, A64::LocationDescriptor{terminal.next}.PC());
//code->mov(code->ABI_PARAM2, reinterpret_cast<u64>(jit_interface)); code->mov(code->ABI_PARAM2.cvt32(), 1);
//code->mov(code->ABI_PARAM3, reinterpret_cast<u64>(cb.user_arg)); code->mov(qword[r15 + offsetof(A64JitState, pc)], code->ABI_PARAM1.cvt32());
//code->mov(MJitStateReg(A64::Reg::PC), code->ABI_PARAM1.cvt32());
code->SwitchMxcsrOnExit(); code->SwitchMxcsrOnExit();
//code->CallFunction(cb.InterpreterFallback); //code->CallFunction(cb.InterpreterFallback);
code->ReturnFromRunCode(true); // TODO: Check cycles code->ReturnFromRunCode(true); // TODO: Check cycles
@ -144,7 +189,7 @@ void A64EmitX64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDesc
code->SwitchToFarCode(); code->SwitchToFarCode();
code->align(16); code->align(16);
code->L(dest); code->L(dest);
//code->mov(MJitStateReg(A64::Reg::PC), A64::LocationDescriptor{terminal.next}.PC()); code->mov(qword[r15 + offsetof(A64JitState, pc)], A64::LocationDescriptor{terminal.next}.PC());
PushRSBHelper(rax, rbx, terminal.next); PushRSBHelper(rax, rbx, terminal.next);
code->ForceReturnFromRunCode(); code->ForceReturnFromRunCode();
code->SwitchToNearCode(); code->SwitchToNearCode();
@ -176,23 +221,23 @@ void A64EmitX64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDesc
EmitTerminal(terminal.else_, initial_location); EmitTerminal(terminal.else_, initial_location);
} }
void A64EmitX64::EmitPatchJg(const IR::LocationDescriptor& /*target_desc*/, CodePtr target_code_ptr) { void A64EmitX64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
const CodePtr patch_location = code->getCurr(); const CodePtr patch_location = code->getCurr();
if (target_code_ptr) { if (target_code_ptr) {
code->jg(target_code_ptr); code->jg(target_code_ptr);
} else { } else {
//code->mov(MJitStateReg(A64::Reg::PC), A64::LocationDescriptor{target_desc}.PC()); code->mov(qword[r15 + offsetof(A64JitState, pc)], A64::LocationDescriptor{target_desc}.PC());
code->jg(code->GetReturnFromRunCodeAddress()); code->jg(code->GetReturnFromRunCodeAddress());
} }
code->EnsurePatchLocationSize(patch_location, 14); code->EnsurePatchLocationSize(patch_location, 14);
} }
void A64EmitX64::EmitPatchJmp(const IR::LocationDescriptor& /*target_desc*/, CodePtr target_code_ptr) { void A64EmitX64::EmitPatchJmp(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
const CodePtr patch_location = code->getCurr(); const CodePtr patch_location = code->getCurr();
if (target_code_ptr) { if (target_code_ptr) {
code->jmp(target_code_ptr); code->jmp(target_code_ptr);
} else { } else {
//code->mov(MJitStateReg(A64::Reg::PC), A64::LocationDescriptor{target_desc}.PC()); code->mov(qword[r15 + offsetof(A64JitState, pc)], A64::LocationDescriptor{target_desc}.PC());
code->jmp(code->GetReturnFromRunCodeAddress()); code->jmp(code->GetReturnFromRunCodeAddress());
} }
code->EnsurePatchLocationSize(patch_location, 13); code->EnsurePatchLocationSize(patch_location, 13);

View file

@ -212,7 +212,7 @@ void EmitX64<JST>::EmitIsZero64(EmitContext& ctx, IR::Inst* inst) {
} }
template <typename JST> template <typename JST>
void EmitX64<JST>::EmitLogicalShiftLeft(EmitContext& ctx, IR::Inst* inst) { void EmitX64<JST>::EmitLogicalShiftLeft32(EmitContext& ctx, IR::Inst* inst) {
auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp); auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp);
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -313,7 +313,41 @@ void EmitX64<JST>::EmitLogicalShiftLeft(EmitContext& ctx, IR::Inst* inst) {
} }
template <typename JST> template <typename JST>
void EmitX64<JST>::EmitLogicalShiftRight(EmitContext& ctx, IR::Inst* inst) { void EmitX64<JST>::EmitLogicalShiftLeft64(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto& operand_arg = args[0];
auto& shift_arg = args[1];
if (shift_arg.IsImmediate()) {
Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(operand_arg);
u8 shift = shift_arg.GetImmediateU8();
if (shift < 64) {
code->shl(result, shift);
} else {
code->xor_(result.cvt32(), result.cvt32());
}
ctx.reg_alloc.DefineValue(inst, result);
} else {
ctx.reg_alloc.Use(shift_arg, HostLoc::RCX);
Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(operand_arg);
Xbyak::Reg64 zero = ctx.reg_alloc.ScratchGpr();
// The x64 SHL instruction masks the shift count by 0x1F before performing the shift.
// ARM differs from the behaviour: It does not mask the count, so shifts above 31 result in zeros.
code->shl(result, code->cl);
code->xor_(zero.cvt32(), zero.cvt32());
code->cmp(code->cl, 64);
code->cmovnb(result, zero);
ctx.reg_alloc.DefineValue(inst, result);
}
}
template <typename JST>
void EmitX64<JST>::EmitLogicalShiftRight32(EmitContext& ctx, IR::Inst* inst) {
auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp); auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp);
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -418,19 +452,36 @@ void EmitX64<JST>::EmitLogicalShiftRight64(EmitContext& ctx, IR::Inst* inst) {
auto& operand_arg = args[0]; auto& operand_arg = args[0];
auto& shift_arg = args[1]; auto& shift_arg = args[1];
ASSERT_MSG(shift_arg.IsImmediate(), "variable 64 bit shifts are not implemented"); if (shift_arg.IsImmediate()) {
ASSERT_MSG(shift_arg.GetImmediateU8() < 64, "shift width clamping is not implemented");
Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(operand_arg); Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(operand_arg);
u8 shift = shift_arg.GetImmediateU8(); u8 shift = shift_arg.GetImmediateU8();
code->shr(result.cvt64(), shift); if (shift < 64) {
code->shr(result, shift);
} else {
code->xor_(result.cvt32(), result.cvt32());
}
ctx.reg_alloc.DefineValue(inst, result);
} else {
ctx.reg_alloc.Use(shift_arg, HostLoc::RCX);
Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(operand_arg);
Xbyak::Reg64 zero = ctx.reg_alloc.ScratchGpr();
// The x64 SHR instruction masks the shift count by 0x1F before performing the shift.
// ARM differs from the behaviour: It does not mask the count, so shifts above 31 result in zeros.
code->shr(result, code->cl);
code->xor_(zero.cvt32(), zero.cvt32());
code->cmp(code->cl, 64);
code->cmovnb(result, zero);
ctx.reg_alloc.DefineValue(inst, result); ctx.reg_alloc.DefineValue(inst, result);
} }
}
template <typename JST> template <typename JST>
void EmitX64<JST>::EmitArithmeticShiftRight(EmitContext& ctx, IR::Inst* inst) { void EmitX64<JST>::EmitArithmeticShiftRight32(EmitContext& ctx, IR::Inst* inst) {
auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp); auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp);
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -519,7 +570,39 @@ void EmitX64<JST>::EmitArithmeticShiftRight(EmitContext& ctx, IR::Inst* inst) {
} }
template <typename JST> template <typename JST>
void EmitX64<JST>::EmitRotateRight(EmitContext& ctx, IR::Inst* inst) { void EmitX64<JST>::EmitArithmeticShiftRight64(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto& operand_arg = args[0];
auto& shift_arg = args[1];
if (shift_arg.IsImmediate()) {
u8 shift = shift_arg.GetImmediateU8();
Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(operand_arg);
code->sar(result, u8(shift < 63 ? shift : 63));
ctx.reg_alloc.DefineValue(inst, result);
} else {
ctx.reg_alloc.UseScratch(shift_arg, HostLoc::RCX);
Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(operand_arg);
Xbyak::Reg64 const63 = ctx.reg_alloc.ScratchGpr();
// The 64-bit x64 SAR instruction masks the shift count by 0x3F before performing the shift.
// ARM differs from the behaviour: It does not mask the count.
// We note that all shift values above 63 have the same behaviour as 63 does, so we saturate `shift` to 63.
code->mov(const63, 63);
code->movzx(code->ecx, code->cl);
code->cmp(code->ecx, u32(63));
code->cmovg(code->ecx, const63);
code->sar(result, code->cl);
ctx.reg_alloc.DefineValue(inst, result);
}
}
template <typename JST>
void EmitX64<JST>::EmitRotateRight32(EmitContext& ctx, IR::Inst* inst) {
auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp); auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp);
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -598,6 +681,30 @@ void EmitX64<JST>::EmitRotateRight(EmitContext& ctx, IR::Inst* inst) {
} }
} }
template <typename JST>
void EmitX64<JST>::EmitRotateRight64(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto& operand_arg = args[0];
auto& shift_arg = args[1];
if (shift_arg.IsImmediate()) {
u8 shift = shift_arg.GetImmediateU8();
Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(operand_arg);
code->ror(result, u8(shift & 0x3F));
ctx.reg_alloc.DefineValue(inst, result);
} else {
ctx.reg_alloc.Use(shift_arg, HostLoc::RCX);
Xbyak::Reg64 result = ctx.reg_alloc.UseScratchGpr(operand_arg);
// x64 ROR instruction does (shift & 0x3F) for us.
code->ror(result, code->cl);
ctx.reg_alloc.DefineValue(inst, result);
}
}
template <typename JST> template <typename JST>
void EmitX64<JST>::EmitRotateRightExtended(EmitContext& ctx, IR::Inst* inst) { void EmitX64<JST>::EmitRotateRightExtended(EmitContext& ctx, IR::Inst* inst) {
auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp); auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp);

View file

@ -48,9 +48,9 @@ bool ArmTranslatorVisitor::arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m,
if (ConditionPassed(cond)) { if (ConditionPassed(cond)) {
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n)); auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m)); auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
auto product = ir.Mul64(n64, m64); auto product = ir.Mul(n64, m64);
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
auto result = ir.Add64(product, addend); auto result = ir.Add(product, addend);
auto lo = ir.LeastSignificantWord(result); auto lo = ir.LeastSignificantWord(result);
auto hi = ir.MostSignificantWord(result).result; auto hi = ir.MostSignificantWord(result).result;
ir.SetRegister(dLo, lo); ir.SetRegister(dLo, lo);
@ -71,7 +71,7 @@ bool ArmTranslatorVisitor::arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m,
if (ConditionPassed(cond)) { if (ConditionPassed(cond)) {
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n)); auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m)); auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
auto result = ir.Mul64(n64, m64); auto result = ir.Mul(n64, m64);
auto lo = ir.LeastSignificantWord(result); auto lo = ir.LeastSignificantWord(result);
auto hi = ir.MostSignificantWord(result).result; auto hi = ir.MostSignificantWord(result).result;
ir.SetRegister(dLo, lo); ir.SetRegister(dLo, lo);
@ -94,7 +94,7 @@ bool ArmTranslatorVisitor::arm_UMAAL(Cond cond, Reg dHi, Reg dLo, Reg m, Reg n)
auto hi64 = ir.ZeroExtendWordToLong(ir.GetRegister(dHi)); auto hi64 = ir.ZeroExtendWordToLong(ir.GetRegister(dHi));
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n)); auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m)); auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
auto result = ir.Add64(ir.Add64(ir.Mul64(n64, m64), hi64), lo64); auto result = ir.Add(ir.Add(ir.Mul(n64, m64), hi64), lo64);
ir.SetRegister(dLo, ir.LeastSignificantWord(result)); ir.SetRegister(dLo, ir.LeastSignificantWord(result));
ir.SetRegister(dHi, ir.MostSignificantWord(result).result); ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
} }
@ -110,7 +110,7 @@ bool ArmTranslatorVisitor::arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m,
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n)); auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m)); auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
auto result = ir.Add64(ir.Mul64(n64, m64), addend); auto result = ir.Add(ir.Mul(n64, m64), addend);
auto lo = ir.LeastSignificantWord(result); auto lo = ir.LeastSignificantWord(result);
auto hi = ir.MostSignificantWord(result).result; auto hi = ir.MostSignificantWord(result).result;
ir.SetRegister(dLo, lo); ir.SetRegister(dLo, lo);
@ -131,7 +131,7 @@ bool ArmTranslatorVisitor::arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m,
if (ConditionPassed(cond)) { if (ConditionPassed(cond)) {
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n)); auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m)); auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
auto result = ir.Mul64(n64, m64); auto result = ir.Mul(n64, m64);
auto lo = ir.LeastSignificantWord(result); auto lo = ir.LeastSignificantWord(result);
auto hi = ir.MostSignificantWord(result).result; auto hi = ir.MostSignificantWord(result).result;
ir.SetRegister(dLo, lo); ir.SetRegister(dLo, lo);
@ -160,7 +160,7 @@ bool ArmTranslatorVisitor::arm_SMLALxy(Cond cond, Reg dHi, Reg dLo, Reg m, bool
: ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)); : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
auto product = ir.SignExtendWordToLong(ir.Mul(n16, m16)); auto product = ir.SignExtendWordToLong(ir.Mul(n16, m16));
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
auto result = ir.Add64(product, addend); auto result = ir.Add(product, addend);
ir.SetRegister(dLo, ir.LeastSignificantWord(result)); ir.SetRegister(dLo, ir.LeastSignificantWord(result));
ir.SetRegister(dHi, ir.MostSignificantWord(result).result); ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
} }
@ -212,7 +212,7 @@ bool ArmTranslatorVisitor::arm_SMLAWy(Cond cond, Reg d, Reg a, Reg m, bool M, Re
if (M) if (M)
m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
auto m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32))); auto m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
auto product = ir.LeastSignificantWord(ir.LogicalShiftRight64(ir.Mul64(n32, m16), ir.Imm8(16))); auto product = ir.LeastSignificantWord(ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16)));
auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0)); auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
ir.SetRegister(d, result_overflow.result); ir.SetRegister(d, result_overflow.result);
ir.OrQFlag(result_overflow.overflow); ir.OrQFlag(result_overflow.overflow);
@ -229,7 +229,7 @@ bool ArmTranslatorVisitor::arm_SMULWy(Cond cond, Reg d, Reg m, bool M, Reg n) {
if (M) if (M)
m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
auto m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32))); auto m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
auto result = ir.LogicalShiftRight64(ir.Mul64(n32, m16), ir.Imm8(16)); auto result = ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16));
ir.SetRegister(d, ir.LeastSignificantWord(result)); ir.SetRegister(d, ir.LeastSignificantWord(result));
} }
return true; return true;
@ -244,7 +244,7 @@ bool ArmTranslatorVisitor::arm_SMMLA(Cond cond, Reg d, Reg a, Reg m, bool R, Reg
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n)); auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m)); auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a)); auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
auto temp = ir.Add64(a64, ir.Mul64(n64, m64)); auto temp = ir.Add(a64, ir.Mul(n64, m64));
auto result_carry = ir.MostSignificantWord(temp); auto result_carry = ir.MostSignificantWord(temp);
auto result = result_carry.result; auto result = result_carry.result;
if (R) if (R)
@ -261,7 +261,7 @@ bool ArmTranslatorVisitor::arm_SMMLS(Cond cond, Reg d, Reg a, Reg m, bool R, Reg
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n)); auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m)); auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a)); auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
auto temp = ir.Sub64(a64, ir.Mul64(n64, m64)); auto temp = ir.Sub(a64, ir.Mul(n64, m64));
auto result_carry = ir.MostSignificantWord(temp); auto result_carry = ir.MostSignificantWord(temp);
auto result = result_carry.result; auto result = result_carry.result;
if (R) if (R)
@ -277,7 +277,7 @@ bool ArmTranslatorVisitor::arm_SMMUL(Cond cond, Reg d, Reg m, bool R, Reg n) {
if (ConditionPassed(cond)) { if (ConditionPassed(cond)) {
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n)); auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m)); auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
auto product = ir.Mul64(n64, m64); auto product = ir.Mul(n64, m64);
auto result_carry = ir.MostSignificantWord(product); auto result_carry = ir.MostSignificantWord(product);
auto result = result_carry.result; auto result = result_carry.result;
if (R) if (R)
@ -332,7 +332,7 @@ bool ArmTranslatorVisitor::arm_SMLALD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M
auto product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo)); auto product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo));
auto product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi)); auto product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi));
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
auto result = ir.Add64(ir.Add64(product_lo, product_hi), addend); auto result = ir.Add(ir.Add(product_lo, product_hi), addend);
ir.SetRegister(dLo, ir.LeastSignificantWord(result)); ir.SetRegister(dLo, ir.LeastSignificantWord(result));
ir.SetRegister(dHi, ir.MostSignificantWord(result).result); ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
} }
@ -380,7 +380,7 @@ bool ArmTranslatorVisitor::arm_SMLSLD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M
auto product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo)); auto product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo));
auto product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi)); auto product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi));
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
auto result = ir.Add64(ir.Sub64(product_lo, product_hi), addend); auto result = ir.Add(ir.Sub(product_lo, product_hi), addend);
ir.SetRegister(dLo, ir.LeastSignificantWord(result)); ir.SetRegister(dLo, ir.LeastSignificantWord(result));
ir.SetRegister(dHi, ir.MostSignificantWord(result).result); ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
} }

View file

@ -373,7 +373,7 @@ std::vector<Matcher<V>> GetDecodeTable() {
//INST(&V::BICS, "BICS (shifted register)", "z1101010ss1mmmmmiiiiiinnnnnddddd"), //INST(&V::BICS, "BICS (shifted register)", "z1101010ss1mmmmmiiiiiinnnnnddddd"),
// Data Processing - Register - Add/Sub (shifted register) // Data Processing - Register - Add/Sub (shifted register)
//INST(&V::ADD_shift, "ADD (shifted register)", "z0001011ss0mmmmmiiiiiinnnnnddddd"), INST(&V::ADD_shift, "ADD (shifted register)", "z0001011ss0mmmmmiiiiiinnnnnddddd"),
//INST(&V::ADDS_shift, "ADDS (shifted register)", "z0101011ss0mmmmmiiiiiinnnnnddddd"), //INST(&V::ADDS_shift, "ADDS (shifted register)", "z0101011ss0mmmmmiiiiiinnnnnddddd"),
//INST(&V::SUB_shift, "SUB (shifted register)", "z1001011ss0mmmmmiiiiiinnnnnddddd"), //INST(&V::SUB_shift, "SUB (shifted register)", "z1001011ss0mmmmmiiiiiinnnnnddddd"),
//INST(&V::SUBS_shift, "SUBS (shifted register)", "z1101011ss0mmmmmiiiiiinnnnnddddd"), //INST(&V::SUBS_shift, "SUBS (shifted register)", "z1101011ss0mmmmmiiiiiinnnnnddddd"),

View file

@ -28,13 +28,13 @@ public:
template <typename T = u32> template <typename T = u32>
T ZeroExtend() const { T ZeroExtend() const {
static_assert(Common::BitSize<T>() <= bit_size); static_assert(Common::BitSize<T>() >= bit_size);
return value; return value;
} }
template <typename T = s32> template <typename T = s32>
T SignExtend() const { T SignExtend() const {
static_assert(Common::BitSize<T>() <= bit_size); static_assert(Common::BitSize<T>() >= bit_size);
return static_cast<T>(Common::SignExtend<bit_size>(value)); return static_cast<T>(Common::SignExtend<bit_size>(value));
} }

View file

@ -0,0 +1,31 @@
/* 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::ADD_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
size_t datasize = sf ? 64 : 32;
if (shift == 0b11) return ReservedValue();
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.Add(operand1, operand2);
X(datasize, Rd, result);
return true;
}
} // namespace A64
} // namespace Dynarmic

View file

@ -0,0 +1,70 @@
/* 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/ir/terminal.h"
#include "frontend/A64/translate/impl/impl.h"
namespace Dynarmic {
namespace A64 {
bool TranslatorVisitor::InterpretThisInstruction() {
ir.SetTerm(IR::Term::Interpret(ir.current_location));
return false;
}
bool TranslatorVisitor::UnpredictableInstruction() {
ASSERT_MSG(false, "UNPREDICTABLE");
return false;
}
bool TranslatorVisitor::ReservedValue() {
ASSERT_MSG(false, "RESERVEDVALUE");
return false;
}
IR::U32U64 TranslatorVisitor::X(size_t bitsize, Reg reg) {
switch (bitsize) {
case 32:
return ir.GetW(reg);
case 64:
return ir.GetX(reg);
default:
ASSERT_MSG(false, "X - get: Invalid bitsize");
return {};
}
}
void TranslatorVisitor::X(size_t bitsize, Reg reg, IR::U32U64 value) {
switch (bitsize) {
case 32:
ir.SetW(reg, value);
return;
case 64:
ir.SetX(reg, value);
return;
default:
ASSERT_MSG(false, "X - set: Invalid bitsize");
}
}
IR::U32U64 TranslatorVisitor::ShiftReg(size_t bitsize, Reg reg, Imm<2> shift, IR::U8 amount) {
auto result = X(bitsize, reg);
switch (shift.ZeroExtend()) {
case 0b00:
return ir.LogicalShiftLeft(result, amount);
case 0b01:
return ir.LogicalShiftRight(result, amount);
case 0b10:
return ir.ArithmeticShiftRight(result, amount);
case 0b11:
return ir.RotateRight(result, amount);
}
ASSERT_MSG(false, "Unreachable");
return {};
}
} // namespace A64
} // namespace Dynarmic

View file

@ -23,6 +23,12 @@ struct TranslatorVisitor final {
bool InterpretThisInstruction(); bool InterpretThisInstruction();
bool UnpredictableInstruction(); bool UnpredictableInstruction();
bool ReservedValue();
IR::U32U64 X(size_t bitsize, Reg reg);
void X(size_t bitsize, Reg reg, IR::U32U64 value);
IR::U32U64 ShiftReg(size_t bitsize, Reg reg, Imm<2> shift, IR::U8 amount);
// Data processing - Immediate - PC relative addressing // Data processing - Immediate - PC relative addressing
bool ADR(Imm<2> immlo, Imm<19> immhi, Reg Rd); bool ADR(Imm<2> immlo, Imm<19> immhi, Reg Rd);

View file

@ -4,6 +4,7 @@
* General Public License version 2 or any later version. * General Public License version 2 or any later version.
*/ */
#include "frontend/A64/decoder/a64.h"
#include "frontend/A64/location_descriptor.h" #include "frontend/A64/location_descriptor.h"
#include "frontend/A64/translate/impl/impl.h" #include "frontend/A64/translate/impl/impl.h"
#include "frontend/A64/translate/translate.h" #include "frontend/A64/translate/translate.h"
@ -12,9 +13,29 @@
namespace Dynarmic { namespace Dynarmic {
namespace A64 { namespace A64 {
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType /*memory_read_code*/) { IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) {
// TODO TranslatorVisitor visitor{descriptor};
return IR::Block{descriptor};
bool should_continue = true;
while (should_continue) {
const u64 pc = visitor.ir.current_location.PC();
const u32 instruction = memory_read_code(pc);
if (auto decoder = Decode<TranslatorVisitor>(instruction)) {
should_continue = decoder->call(visitor, instruction);
} else {
should_continue = visitor.InterpretThisInstruction();
}
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4);
visitor.ir.block.CycleCount()++;
}
ASSERT_MSG(visitor.ir.block.HasTerminal(), "Terminal has not been set");
visitor.ir.block.SetEndLocation(visitor.ir.current_location);
return std::move(visitor.ir.block);
} }
} // namespace A64 } // namespace A64

View file

@ -14,6 +14,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "frontend/A32/types.h" #include "frontend/A32/types.h"
#include "frontend/A64/types.h"
#include "frontend/ir/basic_block.h" #include "frontend/ir/basic_block.h"
#include "frontend/ir/opcodes.h" #include "frontend/ir/opcodes.h"
@ -22,7 +23,7 @@ namespace IR {
void Block::AppendNewInst(Opcode opcode, std::initializer_list<IR::Value> args) { void Block::AppendNewInst(Opcode opcode, std::initializer_list<IR::Value> args) {
IR::Inst* inst = new(instruction_alloc_pool->Alloc()) IR::Inst(opcode); IR::Inst* inst = new(instruction_alloc_pool->Alloc()) IR::Inst(opcode);
DEBUG_ASSERT(args.size() == inst->NumArgs()); ASSERT(args.size() == inst->NumArgs());
std::for_each(args.begin(), args.end(), [&inst, index = size_t(0)](const auto& arg) mutable { std::for_each(args.begin(), args.end(), [&inst, index = size_t(0)](const auto& arg) mutable {
inst->SetArg(index, arg); inst->SetArg(index, arg);
@ -165,6 +166,10 @@ std::string DumpBlock(const IR::Block& block) {
return A32::RegToString(arg.GetA32RegRef()); return A32::RegToString(arg.GetA32RegRef());
case Type::A32ExtReg: case Type::A32ExtReg:
return A32::ExtRegToString(arg.GetA32ExtRegRef()); return A32::ExtRegToString(arg.GetA32ExtRegRef());
case Type::A64Reg:
return A64::RegToString(arg.GetA64RegRef());
case Type::A64Vec:
return A64::VecToString(arg.GetA64VecRef());
default: default:
return "<unknown immediate type>"; return "<unknown immediate type>";
} }

View file

@ -70,29 +70,25 @@ U1 IREmitter::IsZero64(const U64& value) {
} }
ResultAndCarry<U32> IREmitter::LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in) { ResultAndCarry<U32> IREmitter::LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in) {
auto result = Inst<U32>(Opcode::LogicalShiftLeft, value_in, shift_amount, carry_in); auto result = Inst<U32>(Opcode::LogicalShiftLeft32, value_in, shift_amount, carry_in);
auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result); auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result);
return {result, carry_out}; return {result, carry_out};
} }
ResultAndCarry<U32> IREmitter::LogicalShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { ResultAndCarry<U32> IREmitter::LogicalShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) {
auto result = Inst<U32>(Opcode::LogicalShiftRight, value_in, shift_amount, carry_in); auto result = Inst<U32>(Opcode::LogicalShiftRight32, value_in, shift_amount, carry_in);
auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result); auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result);
return {result, carry_out}; return {result, carry_out};
} }
U64 IREmitter::LogicalShiftRight64(const U64& value_in, const U8& shift_amount) {
return Inst<U64>(Opcode::LogicalShiftRight64, value_in, shift_amount);
}
ResultAndCarry<U32> IREmitter::ArithmeticShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { ResultAndCarry<U32> IREmitter::ArithmeticShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) {
auto result = Inst<U32>(Opcode::ArithmeticShiftRight, value_in, shift_amount, carry_in); auto result = Inst<U32>(Opcode::ArithmeticShiftRight32, value_in, shift_amount, carry_in);
auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result); auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result);
return {result, carry_out}; return {result, carry_out};
} }
ResultAndCarry<U32> IREmitter::RotateRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { ResultAndCarry<U32> IREmitter::RotateRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) {
auto result = Inst<U32>(Opcode::RotateRight, value_in, shift_amount, carry_in); auto result = Inst<U32>(Opcode::RotateRight32, value_in, shift_amount, carry_in);
auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result); auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result);
return {result, carry_out}; return {result, carry_out};
} }
@ -103,6 +99,42 @@ ResultAndCarry<U32> IREmitter::RotateRightExtended(const U32& value_in, const U1
return {result, carry_out}; return {result, carry_out};
} }
U64 IREmitter::LogicalShiftRight(const U64& value_in, const U8& shift_amount) {
return Inst<U64>(Opcode::LogicalShiftRight64, value_in, shift_amount);
}
U32U64 IREmitter::LogicalShiftLeft(const U32U64& value_in, const U8& shift_amount) {
if (value_in.GetType() == Type::U32) {
return Inst<U32>(Opcode::LogicalShiftLeft32, value_in, shift_amount, Imm1(0));
} else {
return Inst<U64>(Opcode::LogicalShiftLeft64, value_in, shift_amount);
}
}
U32U64 IREmitter::LogicalShiftRight(const U32U64& value_in, const U8& shift_amount) {
if (value_in.GetType() == Type::U32) {
return Inst<U32>(Opcode::LogicalShiftRight32, value_in, shift_amount, Imm1(0));
} else {
return Inst<U64>(Opcode::LogicalShiftRight64, value_in, shift_amount);
}
}
U32U64 IREmitter::ArithmeticShiftRight(const U32U64& value_in, const U8& shift_amount) {
if (value_in.GetType() == Type::U32) {
return Inst<U32>(Opcode::ArithmeticShiftRight32, value_in, shift_amount, Imm1(0));
} else {
return Inst<U64>(Opcode::ArithmeticShiftRight64, value_in, shift_amount);
}
}
U32U64 IREmitter::RotateRight(const U32U64& value_in, const U8& shift_amount) {
if (value_in.GetType() == Type::U32) {
return Inst<U32>(Opcode::RotateRight32, value_in, shift_amount, Imm1(0));
} else {
return Inst<U64>(Opcode::RotateRight64, value_in, shift_amount);
}
}
ResultAndCarryAndOverflow<U32> IREmitter::AddWithCarry(const Value& a, const Value& b, const U1& carry_in) { ResultAndCarryAndOverflow<U32> IREmitter::AddWithCarry(const Value& a, const Value& b, const U1& carry_in) {
auto result = Inst<U32>(Opcode::AddWithCarry, a, b, carry_in); auto result = Inst<U32>(Opcode::AddWithCarry, a, b, carry_in);
auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result); auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result);
@ -114,10 +146,19 @@ U32 IREmitter::Add(const U32& a, const U32& b) {
return Inst<U32>(Opcode::AddWithCarry, a, b, Imm1(0)); return Inst<U32>(Opcode::AddWithCarry, a, b, Imm1(0));
} }
U64 IREmitter::Add64(const U64& a, const U64& b) { U64 IREmitter::Add(const U64& a, const U64& b) {
return Inst<U64>(Opcode::Add64, a, b); return Inst<U64>(Opcode::Add64, a, b);
} }
U32U64 IREmitter::Add(const U32U64& a, const U32U64& b) {
ASSERT(a.GetType() == b.GetType());
if (a.GetType() == Type::U32) {
return Inst<U32>(Opcode::AddWithCarry, a, b, Imm1(0));
} else {
return Inst<U64>(Opcode::Add64, a, b);
}
}
ResultAndCarryAndOverflow<U32> IREmitter::SubWithCarry(const U32& a, const U32& b, const U1& carry_in) { ResultAndCarryAndOverflow<U32> IREmitter::SubWithCarry(const U32& a, const U32& b, const U1& carry_in) {
// This is equivalent to AddWithCarry(a, Not(b), carry_in). // This is equivalent to AddWithCarry(a, Not(b), carry_in).
auto result = Inst<U32>(Opcode::SubWithCarry, a, b, carry_in); auto result = Inst<U32>(Opcode::SubWithCarry, a, b, carry_in);
@ -130,7 +171,7 @@ U32 IREmitter::Sub(const U32& a, const U32& b) {
return Inst<U32>(Opcode::SubWithCarry, a, b, Imm1(1)); return Inst<U32>(Opcode::SubWithCarry, a, b, Imm1(1));
} }
U64 IREmitter::Sub64(const U64& a, const U64& b) { U64 IREmitter::Sub(const U64& a, const U64& b) {
return Inst<U64>(Opcode::Sub64, a, b); return Inst<U64>(Opcode::Sub64, a, b);
} }
@ -138,7 +179,7 @@ U32 IREmitter::Mul(const U32& a, const U32& b) {
return Inst<U32>(Opcode::Mul, a, b); return Inst<U32>(Opcode::Mul, a, b);
} }
U64 IREmitter::Mul64(const U64& a, const U64& b) { U64 IREmitter::Mul(const U64& a, const U64& b) {
return Inst<U64>(Opcode::Mul64, a, b); return Inst<U64>(Opcode::Mul64, a, b);
} }

View file

@ -84,18 +84,23 @@ public:
ResultAndCarry<U32> LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in); ResultAndCarry<U32> LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in);
ResultAndCarry<U32> LogicalShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in); ResultAndCarry<U32> LogicalShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in);
U64 LogicalShiftRight64(const U64& value_in, const U8& shift_amount);
ResultAndCarry<U32> ArithmeticShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in); ResultAndCarry<U32> ArithmeticShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in);
ResultAndCarry<U32> RotateRight(const U32& value_in, const U8& shift_amount, const U1& carry_in); ResultAndCarry<U32> RotateRight(const U32& value_in, const U8& shift_amount, const U1& carry_in);
U64 LogicalShiftRight(const U64& value_in, const U8& shift_amount);
U32U64 LogicalShiftLeft(const U32U64& value_in, const U8& shift_amount);
U32U64 LogicalShiftRight(const U32U64& value_in, const U8& shift_amount);
U32U64 ArithmeticShiftRight(const U32U64& value_in, const U8& shift_amount);
U32U64 RotateRight(const U32U64& value_in, const U8& shift_amount);
ResultAndCarry<U32> RotateRightExtended(const U32& value_in, const U1& carry_in); ResultAndCarry<U32> RotateRightExtended(const U32& value_in, const U1& carry_in);
ResultAndCarryAndOverflow<U32> AddWithCarry(const Value& a, const Value& b, const U1& carry_in); ResultAndCarryAndOverflow<U32> AddWithCarry(const Value& a, const Value& b, const U1& carry_in);
U32 Add(const U32& a, const U32& b); U32 Add(const U32& a, const U32& b);
U64 Add64(const U64& a, const U64& b); U64 Add(const U64& a, const U64& b);
U32U64 Add(const U32U64& a, const U32U64& b);
ResultAndCarryAndOverflow<U32> SubWithCarry(const U32& a, const U32& b, const U1& carry_in); ResultAndCarryAndOverflow<U32> SubWithCarry(const U32& a, const U32& b, const U1& carry_in);
U32 Sub(const U32& a, const U32& b); U32 Sub(const U32& a, const U32& b);
U64 Sub64(const U64& a, const U64& b); U64 Sub(const U64& a, const U64& b);
U32 Mul(const U32& a, const U32& b); U32 Mul(const U32& a, const U32& b);
U64 Mul64(const U64& a, const U64& b); U64 Mul(const U64& a, const U64& b);
U32 And(const U32& a, const U32& b); U32 And(const U32& a, const U32& b);
U32 Eor(const U32& a, const U32& b); U32 Eor(const U32& a, const U32& b);
U32 Or(const U32& a, const U32& b); U32 Or(const U32& a, const U32& b);

View file

@ -13,18 +13,21 @@ namespace Dynarmic {
namespace IR { namespace IR {
bool Inst::IsArithmeticShift() const { bool Inst::IsArithmeticShift() const {
return op == Opcode::ArithmeticShiftRight; return op == Opcode::ArithmeticShiftRight32 ||
op == Opcode::ArithmeticShiftRight64;
} }
bool Inst::IsCircularShift() const { bool Inst::IsCircularShift() const {
return op == Opcode::RotateRight || return op == Opcode::RotateRight32 ||
op == Opcode::RotateRight64 ||
op == Opcode::RotateRightExtended; op == Opcode::RotateRightExtended;
} }
bool Inst::IsLogicalShift() const { bool Inst::IsLogicalShift() const {
switch (op) { switch (op) {
case Opcode::LogicalShiftLeft: case Opcode::LogicalShiftLeft32:
case Opcode::LogicalShiftRight: case Opcode::LogicalShiftLeft64:
case Opcode::LogicalShiftRight32:
case Opcode::LogicalShiftRight64: case Opcode::LogicalShiftRight64:
return true; return true;
@ -133,6 +136,8 @@ bool Inst::ReadsFromCoreRegister() const {
case Opcode::A32GetRegister: case Opcode::A32GetRegister:
case Opcode::A32GetExtendedRegister32: case Opcode::A32GetExtendedRegister32:
case Opcode::A32GetExtendedRegister64: case Opcode::A32GetExtendedRegister64:
case Opcode::A64GetW:
case Opcode::A64GetX:
return true; return true;
default: default:
@ -146,6 +151,8 @@ bool Inst::WritesToCoreRegister() const {
case Opcode::A32SetExtendedRegister32: case Opcode::A32SetExtendedRegister32:
case Opcode::A32SetExtendedRegister64: case Opcode::A32SetExtendedRegister64:
case Opcode::A32BXWritePC: case Opcode::A32BXWritePC:
case Opcode::A64SetW:
case Opcode::A64SetX:
return true; return true;
default: default:

View file

@ -28,9 +28,11 @@ struct Meta {
static const std::map<Opcode, Meta> opcode_info {{ static const std::map<Opcode, Meta> opcode_info {{
#define OPCODE(name, type, ...) { Opcode::name, { #name, type, { __VA_ARGS__ } } }, #define OPCODE(name, type, ...) { Opcode::name, { #name, type, { __VA_ARGS__ } } },
#define A32OPC(name, type, ...) { Opcode::A32##name, { #name, type, { __VA_ARGS__ } } }, #define A32OPC(name, type, ...) { Opcode::A32##name, { #name, type, { __VA_ARGS__ } } },
#define A64OPC(name, type, ...) { Opcode::A64##name, { #name, type, { __VA_ARGS__ } } },
#include "opcodes.inc" #include "opcodes.inc"
#undef OPCODE #undef OPCODE
#undef A32OPC #undef A32OPC
#undef A64OPC
}}; }};
} // namespace OpcodeInfo } // namespace OpcodeInfo

View file

@ -18,9 +18,11 @@ namespace IR {
enum class Opcode { enum class Opcode {
#define OPCODE(name, type, ...) name, #define OPCODE(name, type, ...) name,
#define A32OPC(name, type, ...) A32##name, #define A32OPC(name, type, ...) A32##name,
#define A64OPC(name, type, ...) A64##name,
#include "opcodes.inc" #include "opcodes.inc"
#undef OPCODE #undef OPCODE
#undef A32OPC #undef A32OPC
#undef A64OPC
NUM_OPCODE NUM_OPCODE
}; };

View file

@ -34,6 +34,12 @@ A32OPC(SetFpscr, T::Void, T::U32,
A32OPC(GetFpscrNZCV, T::U32, ) A32OPC(GetFpscrNZCV, T::U32, )
A32OPC(SetFpscrNZCV, T::Void, T::U32, ) A32OPC(SetFpscrNZCV, T::Void, T::U32, )
// A64 Context getters/setters
A64OPC(GetW, T::U32, T::A64Reg )
A64OPC(GetX, T::U64, T::A64Reg )
A64OPC(SetW, T::Void, T::A64Reg, T::U32 )
A64OPC(SetX, T::Void, T::A64Reg, T::U64 )
// Hints // Hints
OPCODE(PushRSB, T::Void, T::U64 ) OPCODE(PushRSB, T::Void, T::U64 )
@ -51,11 +57,14 @@ OPCODE(LeastSignificantByte, T::U8, T::U32
OPCODE(MostSignificantBit, T::U1, T::U32 ) OPCODE(MostSignificantBit, T::U1, T::U32 )
OPCODE(IsZero, T::U1, T::U32 ) OPCODE(IsZero, T::U1, T::U32 )
OPCODE(IsZero64, T::U1, T::U64 ) OPCODE(IsZero64, T::U1, T::U64 )
OPCODE(LogicalShiftLeft, T::U32, T::U32, T::U8, T::U1 ) OPCODE(LogicalShiftLeft32, T::U32, T::U32, T::U8, T::U1 )
OPCODE(LogicalShiftRight, 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 )
OPCODE(LogicalShiftRight64, T::U64, T::U64, T::U8 ) OPCODE(LogicalShiftRight64, T::U64, T::U64, T::U8 )
OPCODE(ArithmeticShiftRight, T::U32, T::U32, T::U8, T::U1 ) OPCODE(ArithmeticShiftRight32, T::U32, T::U32, T::U8, T::U1 )
OPCODE(RotateRight, T::U32, T::U32, T::U8, T::U1 ) OPCODE(ArithmeticShiftRight64, T::U64, T::U64, T::U8 )
OPCODE(RotateRight32, T::U32, T::U32, T::U8, T::U1 )
OPCODE(RotateRight64, T::U64, T::U64, T::U8 )
OPCODE(RotateRightExtended, T::U32, T::U32, T::U1 ) OPCODE(RotateRightExtended, T::U32, T::U32, T::U1 )
OPCODE(AddWithCarry, T::U32, T::U32, T::U32, T::U1 ) OPCODE(AddWithCarry, T::U32, T::U32, T::U32, T::U1 )
OPCODE(SubWithCarry, T::U32, T::U32, T::U32, T::U1 ) OPCODE(SubWithCarry, T::U32, T::U32, T::U32, T::U1 )

View file

@ -6,6 +6,8 @@
#pragma once #pragma once
#include <type_traits>
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "frontend/A32/types.h" #include "frontend/A32/types.h"
@ -76,9 +78,8 @@ class TypedValue final : public Value {
public: public:
TypedValue() : Value() {} TypedValue() : Value() {}
template <Type other_type> template <Type other_type, typename = std::enable_if_t<(other_type & type_) != Type::Void>>
/* implicit */ TypedValue(const TypedValue<other_type>& value) : Value(value) { /* implicit */ TypedValue(const TypedValue<other_type>& value) : Value(value) {
static_assert((other_type & type_) != Type::Void);
ASSERT((value.GetType() & type_) != Type::Void); ASSERT((value.GetType() & type_) != Type::Void);
} }
@ -92,6 +93,7 @@ using U8 = TypedValue<Type::U8>;
using U16 = TypedValue<Type::U16>; using U16 = TypedValue<Type::U16>;
using U32 = TypedValue<Type::U32>; using U32 = TypedValue<Type::U32>;
using U64 = TypedValue<Type::U64>; using U64 = TypedValue<Type::U64>;
using U32U64 = TypedValue<Type::U32 | Type::U64>;
using F32 = TypedValue<Type::F32>; using F32 = TypedValue<Type::F32>;
using F64 = TypedValue<Type::F64>; using F64 = TypedValue<Type::F64>;
using F128 = TypedValue<Type::F128>; using F128 = TypedValue<Type::F128>;

View file

@ -23,10 +23,10 @@ void ConstantPropagation(IR::Block& block, const A32::UserCallbacks::Memory& mem
} }
break; break;
} }
case IR::Opcode::LogicalShiftLeft: case IR::Opcode::LogicalShiftLeft32:
case IR::Opcode::LogicalShiftRight: case IR::Opcode::LogicalShiftRight32:
case IR::Opcode::ArithmeticShiftRight: case IR::Opcode::ArithmeticShiftRight32:
case IR::Opcode::RotateRight: { case IR::Opcode::RotateRight32: {
if (!inst.GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp)) { if (!inst.GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp)) {
inst.SetArg(2, IR::Value(false)); inst.SetArg(2, IR::Value(false));
} }

View file

@ -1,5 +1,5 @@
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage * Copyright (c) 2018 MerryMage
* This software may be used and distributed according to the terms of the GNU * This software may be used and distributed according to the terms of the GNU
* General Public License version 2 or any later version. * General Public License version 2 or any later version.
*/ */
@ -14,6 +14,7 @@
#include "common/common_types.h" #include "common/common_types.h"
class TestEnv final : public Dynarmic::A64::UserCallbacks { class TestEnv final : public Dynarmic::A64::UserCallbacks {
public:
u64 ticks_left = 0; u64 ticks_left = 0;
std::array<u32, 3000> code_mem{}; std::array<u32, 3000> code_mem{};
@ -22,7 +23,7 @@ class TestEnv final : public Dynarmic::A64::UserCallbacks {
size_t index = vaddr / sizeof(u32); size_t index = vaddr / sizeof(u32);
return code_mem[index]; return code_mem[index];
} }
ASSERT_MSG(false, "MemoryReadCode(%llx)", vaddr); return 0x14000000; // B .
} }
std::uint8_t MemoryRead8(u64 vaddr) override { ASSERT_MSG(false, "MemoryRead8(%llx)", vaddr); } std::uint8_t MemoryRead8(u64 vaddr) override { ASSERT_MSG(false, "MemoryRead8(%llx)", vaddr); }
@ -49,10 +50,25 @@ class TestEnv final : public Dynarmic::A64::UserCallbacks {
std::uint64_t GetTicksRemaining() override { std::uint64_t GetTicksRemaining() override {
return ticks_left; return ticks_left;
} }
}; };
TEST_CASE("A64", "[a64]") { TEST_CASE("A64: ADD", "[a64]") {
TestEnv env; TestEnv env;
Dynarmic::A64::Jit jit{Dynarmic::A64::UserConfig{&env}}; Dynarmic::A64::Jit jit{Dynarmic::A64::UserConfig{&env}};
env.code_mem[0] = 0x8b020020; // ADD X0, X1, X2
env.code_mem[1] = 0x14000000; // B .
jit.SetRegister(0, 0);
jit.SetRegister(1, 1);
jit.SetRegister(2, 2);
jit.SetPC(0);
env.ticks_left = 2;
jit.Run();
REQUIRE(jit.GetRegister(0) == 3);
REQUIRE(jit.GetRegister(1) == 1);
REQUIRE(jit.GetRegister(2) == 2);
REQUIRE(jit.GetPC() == 4);
} }