diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f194b17e..ab4f275b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -61,6 +61,7 @@ add_library(dynarmic frontend/A64/location_descriptor.h frontend/A64/translate/impl/branch.cpp frontend/A64/translate/impl/data_processing_addsub.cpp + frontend/A64/translate/impl/data_processing_bitfield.cpp frontend/A64/translate/impl/data_processing_logical.cpp frontend/A64/translate/impl/data_processing_pcrel.cpp frontend/A64/translate/impl/exception_generating.cpp diff --git a/src/common/bit_util.h b/src/common/bit_util.h index 40de5d12..15b6ce5a 100644 --- a/src/common/bit_util.h +++ b/src/common/bit_util.h @@ -101,6 +101,8 @@ inline int HighestSetBit(T value) { template inline T Ones(size_t count) { ASSERT_MSG(count <= BitSize(), "count larger than bitsize of T"); + if (count == BitSize()) + return ~static_cast(0); return ~(~static_cast(0) << count); } diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index c609fc5f..c3eeae37 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -20,9 +20,9 @@ INST(MOVZ, "MOVZ", "z1010 INST(MOVK, "MOVK", "z11100101ssiiiiiiiiiiiiiiiiddddd") // Data processing - Immediate - Bitfield -//INST(SBFM, "SBFM", "z00100110Nrrrrrrssssssnnnnnddddd") -//INST(BFM, "BFM", "z01100110Nrrrrrrssssssnnnnnddddd") -//INST(UBFM, "UBFM", "z10100110Nrrrrrrssssssnnnnnddddd") +INST(SBFM, "SBFM", "z00100110Nrrrrrrssssssnnnnnddddd") +INST(BFM, "BFM", "z01100110Nrrrrrrssssssnnnnnddddd") +INST(UBFM, "UBFM", "z10100110Nrrrrrrssssssnnnnnddddd") // Data processing - Immediate - Extract //INST(EXTR, "EXTR", "z00100111N0mmmmmssssssnnnnnddddd") diff --git a/src/frontend/A64/translate/impl/data_processing_bitfield.cpp b/src/frontend/A64/translate/impl/data_processing_bitfield.cpp new file mode 100644 index 00000000..fd329fd2 --- /dev/null +++ b/src/frontend/A64/translate/impl/data_processing_bitfield.cpp @@ -0,0 +1,81 @@ +/* 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 { + +static IR::U32U64 ReplicateBit(IREmitter& ir, const IR::U32U64& value, u8 bit_position_to_replicate) { + u8 datasize = value.GetType() == IR::Type::U64 ? 64 : 32; + auto bit = ir.LogicalShiftLeft(value, ir.Imm8(datasize - 1 - bit_position_to_replicate)); + return ir.ArithmeticShiftRight(bit, ir.Imm8(datasize - 1)); +} + +bool TranslatorVisitor::SBFM(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(); + if (!sf && (N || immr.Bit<5>() || imms.Bit<5>())) return ReservedValue(); + + u8 R = immr.ZeroExtend(); + u8 S = imms.ZeroExtend(); + auto masks = DecodeBitMasks(N, imms, immr, false); + if (!masks) return ReservedValue(); + + auto src = X(datasize, Rn); + + auto bot = ir.And(ir.RotateRight(src, ir.Imm8(R)), I(datasize, masks->wmask)); + auto top = ReplicateBit(ir, src, S); + + top = ir.And(top, I(datasize, ~masks->tmask)); + bot = ir.And(bot, I(datasize, masks->tmask)); + X(datasize, Rd, ir.Or(top, bot)); + + return true; +} + +bool TranslatorVisitor::BFM(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(); + if (!sf && (N || immr.Bit<5>() || imms.Bit<5>())) return ReservedValue(); + + u8 R = immr.ZeroExtend(); + auto masks = DecodeBitMasks(N, imms, immr, false); + if (!masks) return ReservedValue(); + + auto dst = X(datasize, Rd); + auto src = X(datasize, Rn); + + auto bot = ir.Or(ir.And(dst, I(datasize, ~masks->wmask)), ir.And(ir.RotateRight(src, ir.Imm8(R)), I(datasize, masks->wmask))); + + X(datasize, Rd, ir.Or(ir.And(dst, I(datasize, ~masks->tmask)), ir.And(bot, I(datasize, masks->tmask)))); + + return true; +} + +bool TranslatorVisitor::UBFM(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(); + if (!sf && (N || immr.Bit<5>() || imms.Bit<5>())) return ReservedValue(); + + u8 R = immr.ZeroExtend(); + auto masks = DecodeBitMasks(N, imms, immr, false); + if (!masks) return ReservedValue(); + + auto src = X(datasize, Rn); + + auto bot = ir.And(ir.RotateRight(src, ir.Imm8(R)), I(datasize, masks->wmask)); + + X(datasize, Rd, ir.And(bot, I(datasize, masks->tmask))); + + return true; +} + +} // namespace A64 +} // namespace Dynarmic diff --git a/src/frontend/A64/translate/impl/exception_generating.cpp b/src/frontend/A64/translate/impl/exception_generating.cpp index de15ebe9..18f7ee91 100644 --- a/src/frontend/A64/translate/impl/exception_generating.cpp +++ b/src/frontend/A64/translate/impl/exception_generating.cpp @@ -10,7 +10,6 @@ namespace Dynarmic { namespace A64 { bool TranslatorVisitor::SVC(Imm<16> imm16) { - printf("translator %x\n", imm16.ZeroExtend()); // ir.PushRSB(ir.current_location.AdvancePC(4)); // TODO ir.SetPC(ir.Imm64(ir.current_location.PC() + 4)); ir.CallSupervisor(imm16.ZeroExtend()); diff --git a/tests/A64/fuzz_with_unicorn.cpp b/tests/A64/fuzz_with_unicorn.cpp index 29307741..ae9b5980 100644 --- a/tests/A64/fuzz_with_unicorn.cpp +++ b/tests/A64/fuzz_with_unicorn.cpp @@ -115,7 +115,7 @@ restart: if (!should_continue) goto restart; for (const auto& ir_inst : block) - if (ir_inst.CausesCPUException() || ir_inst.IsMemoryWrite() || ir_inst.GetOpcode() == IR::Opcode::A64ExceptionRaised) + if (ir_inst.IsMemoryWrite() || ir_inst.GetOpcode() == IR::Opcode::A64ExceptionRaised || ir_inst.GetOpcode() == IR::Opcode::A64CallSupervisor) goto restart; return instruction; @@ -155,13 +155,15 @@ static void TestInstance(const std::array& regs, const std::vector } TEST_CASE("A64: Single random instruction", "[a64]") { - for (size_t iteration = 0; iteration < 10000; ++iteration) { + for (size_t iteration = 0; iteration < 100000; ++iteration) { std::array regs; std::generate_n(regs.begin(), 31, []{ return RandInt(0, ~u64(0)); }); std::vector instructions; instructions.push_back(GenRandomInst(0)); u32 pstate = RandInt(0, 0xF) << 28; + // printf("%08x\n", instructions[0]); + TestInstance(regs, instructions, pstate); } }