From a5a210a9a515b18917ad4ade155916de29a38d1b Mon Sep 17 00:00:00 2001 From: MerryMage Date: Mon, 3 May 2021 23:30:59 +0100 Subject: [PATCH] T32: Add ASIMD instructions --- .../A32/translate/translate_thumb.cpp | 19 ++++++++++++++ tests/A32/fuzz_arm.cpp | 25 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/frontend/A32/translate/translate_thumb.cpp b/src/frontend/A32/translate/translate_thumb.cpp index 9f93c11d..a1a47cfc 100644 --- a/src/frontend/A32/translate/translate_thumb.cpp +++ b/src/frontend/A32/translate/translate_thumb.cpp @@ -9,6 +9,7 @@ #include "common/assert.h" #include "common/bit_util.h" +#include "frontend/A32/decoder/asimd.h" #include "frontend/A32/decoder/thumb16.h" #include "frontend/A32/decoder/thumb32.h" #include "frontend/A32/decoder/vfp.h" @@ -64,6 +65,20 @@ std::tuple ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFu return std::make_tuple(static_cast((first_part << 16) | second_part), ThumbInstSize::Thumb32); } +// Convert from thumb ASIMD format to ARM ASIMD format. +u32 ConvertASIMDInstruction(u32 thumb_instruction) { + if ((thumb_instruction & 0xEF000000) == 0xEF000000) { + const bool U = Common::Bit<28>(thumb_instruction); + return 0xF2000000 | (U << 24) | (thumb_instruction & 0x00FFFFFF); + } + + if ((thumb_instruction & 0xFF000000) == 0xF9000000) { + return 0xF4000000 | (thumb_instruction & 0x00FFFFFF); + } + + return 0xF7F0A000; // UDF +} + } // local namespace IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options) { @@ -92,6 +107,8 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType m } else if ((thumb_instruction & 0xEC000000) == 0xEC000000) { if (const auto vfp_decoder = DecodeVFP(thumb_instruction)) { should_continue = vfp_decoder->get().call(visitor, thumb_instruction); + } else if (const auto asimd_decoder = DecodeASIMD(ConvertASIMDInstruction(thumb_instruction))) { + should_continue = asimd_decoder->get().call(visitor, ConvertASIMDInstruction(thumb_instruction)); } else { should_continue = visitor.thumb32_UDF(); } @@ -144,6 +161,8 @@ bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descri } else if ((thumb_instruction & 0xEC000000) == 0xEC000000) { if (const auto vfp_decoder = DecodeVFP(thumb_instruction)) { should_continue = vfp_decoder->get().call(visitor, thumb_instruction); + } else if (const auto asimd_decoder = DecodeASIMD(ConvertASIMDInstruction(thumb_instruction))) { + should_continue = asimd_decoder->get().call(visitor, ConvertASIMDInstruction(thumb_instruction)); } else { should_continue = visitor.thumb32_UDF(); } diff --git a/tests/A32/fuzz_arm.cpp b/tests/A32/fuzz_arm.cpp index 8dcbf7ed..1e90799b 100644 --- a/tests/A32/fuzz_arm.cpp +++ b/tests/A32/fuzz_arm.cpp @@ -164,6 +164,12 @@ std::vector GenRandomThumbInst(u32 pc, bool is_last_inst, A32::ITState it_s #undef INST }; + const std::vector> asimd_list { +#define INST(fn, name, bitstring) {#fn, bitstring}, +#include "frontend/A32/decoder/asimd.inc" +#undef INST + }; + std::vector generators; std::vector invalid; @@ -189,6 +195,8 @@ std::vector GenRandomThumbInst(u32 pc, bool is_last_inst, A32::ITState it_s // Unicorn has incorrect implementation (incorrect rounding and unsets CPSR.T??) "vfp_VCVT_to_fixed", "vfp_VCVT_from_fixed", + "asimd_VRECPS", // Unicorn does not fuse the multiply and subtraction, resulting in being off by 1ULP. + "asimd_VRSQRTS", // Unicorn does not fuse the multiply and subtraction, resulting in being off by 1ULP. }; for (const auto& [fn, bitstring] : list) { @@ -209,6 +217,23 @@ std::vector GenRandomThumbInst(u32 pc, bool is_last_inst, A32::ITState it_s } generators.emplace_back(InstructionGenerator{bitstring.c_str()}); } + for (const auto& [fn, bs] : asimd_list) { + std::string bitstring = bs; + if (bitstring.substr(0, 7) == "1111001") { + const char U = bitstring[7]; + bitstring.replace(0, 8, "111-1111"); + bitstring[3] = U; + } else if (bitstring.substr(0, 8) == "11110100") { + bitstring.replace(0, 8, "11111001"); + } else { + ASSERT_FALSE("Unhandled ASIMD instruction: {} {}", fn, bs); + } + if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) { + invalid.emplace_back(InstructionGenerator{bitstring.c_str()}); + continue; + } + generators.emplace_back(InstructionGenerator{bitstring.c_str()}); + } return InstructionGeneratorInfo{generators, invalid}; }();