diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 67ecc0a6..176613f4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -75,6 +75,7 @@ add_library(dynarmic frontend/A64/translate/impl/data_processing_shift.cpp frontend/A64/translate/impl/exception_generating.cpp frontend/A64/translate/impl/floating_point_compare.cpp + frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp frontend/A64/translate/impl/floating_point_data_processing_two_register.cpp frontend/A64/translate/impl/impl.cpp frontend/A64/translate/impl/impl.h diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index ad3a01a0..4c6b4445 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -933,7 +933,7 @@ INST(FCMP_float, "FCMP", "00011 INST(FCMPE_float, "FCMPE", "00011110yy1mmmmm001000nnnnn1o000") // Data Processing - FP and SIMD - Floating point immediate -//INST(FMOV_float_imm, "FMOV (scalar, immediate)", "00011110yy1iiiiiiii10000000ddddd") +INST(FMOV_float_imm, "FMOV (scalar, immediate)", "00011110yy1iiiiiiii10000000ddddd") // Data Processing - FP and SIMD - Floating point conditional compare //INST(FCCMP_float, "FCCMP", "00011110yy1mmmmmcccc01nnnnn0ffff") diff --git a/src/frontend/A64/imm.h b/src/frontend/A64/imm.h index 69fd2e32..23b4b71c 100644 --- a/src/frontend/A64/imm.h +++ b/src/frontend/A64/imm.h @@ -44,6 +44,12 @@ public: return Common::Bit(value); } + template + T Bits() const { + static_assert(Common::BitSize() >= end_bit - begin_bit + 1); + return static_cast(Common::Bits(value)); + } + bool operator==(const Imm& other) const { return value == other.value; } diff --git a/src/frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp b/src/frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp new file mode 100644 index 00000000..c38187d3 --- /dev/null +++ b/src/frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp @@ -0,0 +1,59 @@ +/* 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 + +#include "frontend/A64/translate/impl/impl.h" + +namespace Dynarmic::A64 { + +static boost::optional GetDataSize(Imm<2> type) { + switch (type.ZeroExtend()) { + case 0b00: + return 32; + case 0b01: + return 64; + case 0b11: + return 16; + } + return boost::none; +} + +bool TranslatorVisitor::FMOV_float_imm(Imm<2> type, Imm<8> imm8, Vec Vd) { + boost::optional datasize = GetDataSize(type); + if (!datasize) { + return UnallocatedEncoding(); + } + + IR::UAny result = [&]() -> IR::UAny { + switch (*datasize) { + case 16: { + const u16 sign = imm8.Bit<7>() ? 1 : 0; + const u16 exp = (imm8.Bit<6>() ? 0b0'1100 : 0b1'0000) | imm8.Bits<4, 5, u16>(); + const u16 fract = imm8.Bits<0, 3, u16>() << 6; + return ir.Imm16((sign << 15) | (exp << 10) | fract); + } + case 32: { + const u32 sign = imm8.Bit<7>() ? 1 : 0; + const u32 exp = (imm8.Bit<6>() ? 0b0111'1100 : 0b1000'0000) | imm8.Bits<4, 5, u32>(); + const u32 fract = imm8.Bits<0, 3, u32>() << 19; + return ir.Imm32((sign << 31) | (exp << 23) | fract); + } + case 64: + default: { + const u64 sign = imm8.Bit<7>() ? 1 : 0; + const u64 exp = (imm8.Bit<6>() ? 0b011'1111'1100 : 0b100'0000'0000) | imm8.Bits<4, 5, u64>(); + const u64 fract = imm8.Bits<0, 3, u64>() << 48; + return ir.Imm64((sign << 63) | (exp << 52) | fract); + } + } + }(); + + V_scalar(*datasize, Vd, result); + return true; +} + +} // namespace Dynarmic::A64 diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index e72bfd23..9198be70 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -18,6 +18,10 @@ U8 IREmitter::Imm8(u8 imm8) { return U8(Value(imm8)); } +U16 IREmitter::Imm16(u16 imm16) { + return U16(Value(imm16)); +} + U32 IREmitter::Imm32(u32 imm32) { return U32(Value(imm32)); } diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index 7c59d186..77dd5955 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -61,6 +61,7 @@ public: U1 Imm1(bool value); U8 Imm8(u8 value); + U16 Imm16(u16 value); U32 Imm32(u32 value); U64 Imm64(u64 value); diff --git a/tests/A64/fuzz_with_unicorn.cpp b/tests/A64/fuzz_with_unicorn.cpp index 4f87d618..9ecc2787 100644 --- a/tests/A64/fuzz_with_unicorn.cpp +++ b/tests/A64/fuzz_with_unicorn.cpp @@ -39,6 +39,7 @@ static std::vector instruction_generators = []{ }; std::vector result; + for (const auto& [fn, bitstring] : list) { if (std::strcmp(fn, "UnallocatedEncoding") == 0) { InstructionGenerator::AddInvalidInstruction(bitstring); @@ -46,6 +47,11 @@ static std::vector instruction_generators = []{ } result.emplace_back(InstructionGenerator{bitstring}); } + + // Manually added exceptions: + // FMOV_float_imm for half-precision floats (QEMU doesn't have half-precision support yet). + InstructionGenerator::AddInvalidInstruction("00011110111iiiiiiii10000000ddddd"); + return result; }();