decoder: Generify the matcher interface (#33)
Gets rid of a bit of duplication while remaining compatible with the current interfaces in place.
This commit is contained in:
parent
943487ecee
commit
f75acd6cfb
11 changed files with 116 additions and 172 deletions
|
@ -59,6 +59,7 @@ set(HEADERS
|
||||||
frontend/arm/types.h
|
frontend/arm/types.h
|
||||||
frontend/decoder/arm.h
|
frontend/decoder/arm.h
|
||||||
frontend/decoder/decoder_detail.h
|
frontend/decoder/decoder_detail.h
|
||||||
|
frontend/decoder/matcher.h
|
||||||
frontend/decoder/thumb16.h
|
frontend/decoder/thumb16.h
|
||||||
frontend/decoder/thumb32.h
|
frontend/decoder/thumb32.h
|
||||||
frontend/decoder/vfp2.h
|
frontend/decoder/vfp2.h
|
||||||
|
|
|
@ -16,60 +16,19 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend/decoder/decoder_detail.h"
|
#include "frontend/decoder/decoder_detail.h"
|
||||||
|
#include "frontend/decoder/matcher.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace Arm {
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
struct ArmMatcher {
|
using ArmMatcher = Matcher<Visitor, u32>;
|
||||||
using CallRetT = mp::return_type_t<decltype(&Visitor::arm_UDF)>;
|
|
||||||
|
|
||||||
ArmMatcher(const char* const name, u32 mask, u32 expect, std::function<CallRetT(Visitor&, u32)> fn)
|
|
||||||
: name(name), mask(mask), expect(expect), fn(fn) {}
|
|
||||||
|
|
||||||
/// Gets the name of this type of instruction.
|
|
||||||
const char* GetName() const {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests to see if the instruction is this type of instruction.
|
|
||||||
* @param instruction The instruction to test
|
|
||||||
* @returns true if the instruction is
|
|
||||||
*/
|
|
||||||
bool Matches(u32 instruction) const {
|
|
||||||
return (instruction & mask) == expect;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the corresponding instruction handler on visitor for this type of instruction.
|
|
||||||
* @param v The visitor to use
|
|
||||||
* @param instruction The instruction to decode.
|
|
||||||
*/
|
|
||||||
CallRetT call(Visitor& v, u32 instruction) const {
|
|
||||||
ASSERT(Matches(instruction));
|
|
||||||
return fn(v, instruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetMask() const {
|
|
||||||
return mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetExpect() const {
|
|
||||||
return expect;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const char* name;
|
|
||||||
u32 mask, expect;
|
|
||||||
std::function<CallRetT(Visitor&, u32)> fn;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
std::vector<ArmMatcher<V>> GetArmDecodeTable() {
|
std::vector<ArmMatcher<V>> GetArmDecodeTable() {
|
||||||
std::vector<ArmMatcher<V>> table = {
|
std::vector<ArmMatcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) detail::detail<ArmMatcher, u32, 32>::GetMatcher<decltype(fn)>(fn, name, bitstring)
|
#define INST(fn, name, bitstring) detail::detail<ArmMatcher<V>>::GetMatcher(fn, name, bitstring)
|
||||||
|
|
||||||
// Branch instructions
|
// Branch instructions
|
||||||
INST(&V::arm_BLX_imm, "BLX (imm)", "1111101hvvvvvvvvvvvvvvvvvvvvvvvv"), // v5
|
INST(&V::arm_BLX_imm, "BLX (imm)", "1111101hvvvvvvvvvvvvvvvvvvvvvvvv"), // v5
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/bit_util.h"
|
||||||
#include "common/mp.h"
|
#include "common/mp.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
|
@ -19,22 +20,25 @@ namespace detail {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper functions for the decoders.
|
* Helper functions for the decoders.
|
||||||
* @tparam MatcherT The type of the matcher. (ARM: ArmMatcher, Thumb16: Thumb16Matcher)
|
*
|
||||||
* @tparam InstructionT The type that represents an instruction. (ARM: u32, Thumb16: u16)
|
* @tparam MatcherT The type of the Matcher to use.
|
||||||
* @tparam instruction_bit_size Bit-size for an instruction. (ARM: 32, Thumb16: 16)
|
|
||||||
*/
|
*/
|
||||||
template<template<typename> class MatcherT, typename InstructionT, size_t instruction_bit_size>
|
template<class MatcherT>
|
||||||
struct detail {
|
struct detail {
|
||||||
private:
|
private:
|
||||||
|
using opcode_type = typename MatcherT::opcode_type;
|
||||||
|
|
||||||
|
static constexpr size_t opcode_bitsize = Common::BitSize<opcode_type>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the mask and the expected value after masking from a given bitstring.
|
* Generates the mask and the expected value after masking from a given bitstring.
|
||||||
* A '0' in a bitstring indicates that a zero must be present at that bit position.
|
* A '0' in a bitstring indicates that a zero must be present at that bit position.
|
||||||
* A '1' in a bitstring indicates that a one must be present at that bit position.
|
* A '1' in a bitstring indicates that a one must be present at that bit position.
|
||||||
*/
|
*/
|
||||||
static auto GetMaskAndExpect(const char* const bitstring) {
|
static auto GetMaskAndExpect(const char* const bitstring) {
|
||||||
InstructionT mask = 0, expect = 0;
|
opcode_type mask = 0, expect = 0;
|
||||||
for (size_t i = 0; i < instruction_bit_size; i++) {
|
for (size_t i = 0; i < opcode_bitsize; i++) {
|
||||||
const size_t bit_position = instruction_bit_size - i - 1;
|
const size_t bit_position = opcode_bitsize - i - 1;
|
||||||
switch (bitstring[i]) {
|
switch (bitstring[i]) {
|
||||||
case '0':
|
case '0':
|
||||||
mask |= 1 << bit_position;
|
mask |= 1 << bit_position;
|
||||||
|
@ -58,13 +62,13 @@ private:
|
||||||
*/
|
*/
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
static auto GetArgInfo(const char* const bitstring) {
|
static auto GetArgInfo(const char* const bitstring) {
|
||||||
std::array<InstructionT, N> masks = {};
|
std::array<opcode_type, N> masks = {};
|
||||||
std::array<size_t, N> shifts = {};
|
std::array<size_t, N> shifts = {};
|
||||||
size_t arg_index = 0;
|
size_t arg_index = 0;
|
||||||
char ch = 0;
|
char ch = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < instruction_bit_size; i++) {
|
for (size_t i = 0; i < opcode_bitsize; i++) {
|
||||||
const size_t bit_position = instruction_bit_size - i - 1;
|
const size_t bit_position = opcode_bitsize - i - 1;
|
||||||
|
|
||||||
if (bitstring[i] == '0' || bitstring[i] == '1' || bitstring[i] == '-') {
|
if (bitstring[i] == '0' || bitstring[i] == '1' || bitstring[i] == '-') {
|
||||||
if (ch != 0) {
|
if (ch != 0) {
|
||||||
|
@ -107,9 +111,9 @@ private:
|
||||||
template<size_t ...iota>
|
template<size_t ...iota>
|
||||||
static auto Make(std::integer_sequence<size_t, iota...>,
|
static auto Make(std::integer_sequence<size_t, iota...>,
|
||||||
CallRetT (Visitor::* const fn)(Args...),
|
CallRetT (Visitor::* const fn)(Args...),
|
||||||
const std::array<InstructionT, sizeof...(iota)> arg_masks,
|
const std::array<opcode_type, sizeof...(iota)> arg_masks,
|
||||||
const std::array<size_t, sizeof...(iota)> arg_shifts) {
|
const std::array<size_t, sizeof...(iota)> arg_shifts) {
|
||||||
return [fn, arg_masks, arg_shifts](Visitor& v, InstructionT instruction) {
|
return [fn, arg_masks, arg_shifts](Visitor& v, opcode_type instruction) {
|
||||||
(void)instruction;
|
(void)instruction;
|
||||||
return (v.*fn)(static_cast<Args>((instruction & arg_masks[iota]) >> arg_shifts[iota])...);
|
return (v.*fn)(static_cast<Args>((instruction & arg_masks[iota]) >> arg_shifts[iota])...);
|
||||||
};
|
};
|
||||||
|
@ -126,7 +130,6 @@ public:
|
||||||
*/
|
*/
|
||||||
template<typename FnT>
|
template<typename FnT>
|
||||||
static auto GetMatcher(FnT fn, const char* const name, const char* const bitstring) {
|
static auto GetMatcher(FnT fn, const char* const name, const char* const bitstring) {
|
||||||
using Visitor = typename mp::FunctionInfo<FnT>::class_type;
|
|
||||||
constexpr size_t args_count = mp::FunctionInfo<FnT>::args_count;
|
constexpr size_t args_count = mp::FunctionInfo<FnT>::args_count;
|
||||||
using Iota = std::make_index_sequence<args_count>;
|
using Iota = std::make_index_sequence<args_count>;
|
||||||
|
|
||||||
|
@ -134,7 +137,7 @@ public:
|
||||||
const auto arg_info = GetArgInfo<args_count>(bitstring);
|
const auto arg_info = GetArgInfo<args_count>(bitstring);
|
||||||
const auto proxy_fn = VisitorCaller<FnT>::Make(Iota(), fn, std::get<0>(arg_info), std::get<1>(arg_info));
|
const auto proxy_fn = VisitorCaller<FnT>::Make(Iota(), fn, std::get<0>(arg_info), std::get<1>(arg_info));
|
||||||
|
|
||||||
return MatcherT<Visitor>(name, std::get<0>(mask_and_expect), std::get<1>(mask_and_expect), proxy_fn);
|
return MatcherT(name, std::get<0>(mask_and_expect), std::get<1>(mask_and_expect), proxy_fn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
78
src/frontend/decoder/matcher.h
Normal file
78
src/frontend/decoder/matcher.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2016 MerryMage
|
||||||
|
* This software may be used and distributed according to the terms of the GNU
|
||||||
|
* General Public License version 2 or any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
namespace Arm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic instruction handling construct.
|
||||||
|
*
|
||||||
|
* @tparam Visitor An arbitrary visitor type that will be passed through
|
||||||
|
* to the function being handled. This type must be the
|
||||||
|
* type of the first parameter in a handler function.
|
||||||
|
*
|
||||||
|
* @tparam OpcodeType Type representing an opcode. This must be the
|
||||||
|
* type of the second parameter in a handler function.
|
||||||
|
*/
|
||||||
|
template <typename Visitor, typename OpcodeType>
|
||||||
|
class Matcher {
|
||||||
|
public:
|
||||||
|
using opcode_type = OpcodeType;
|
||||||
|
using handler_return_type = typename Visitor::instruction_return_type;
|
||||||
|
using handler_function = std::function<handler_return_type(Visitor&, opcode_type)>;
|
||||||
|
|
||||||
|
Matcher(const char* const name, opcode_type mask, opcode_type expected, handler_function func)
|
||||||
|
: name{name}, mask{mask}, expected{expected}, fn{std::move(func)} {}
|
||||||
|
|
||||||
|
/// Gets the name of this type of instruction.
|
||||||
|
const char* GetName() const {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the mask for this instruction.
|
||||||
|
opcode_type GetMask() const {
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the expected value after masking for this instruction.
|
||||||
|
opcode_type GetExpected() const {
|
||||||
|
return expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests to see if the given instruction is the instruction this matcher represents.
|
||||||
|
* @param instruction The instruction to test
|
||||||
|
* @returns true if the given instruction matches.
|
||||||
|
*/
|
||||||
|
bool Matches(opcode_type instruction) const {
|
||||||
|
return (instruction & mask) == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls the corresponding instruction handler on visitor for this type of instruction.
|
||||||
|
* @param v The visitor to use
|
||||||
|
* @param instruction The instruction to decode.
|
||||||
|
*/
|
||||||
|
handler_return_type call(Visitor& v, opcode_type instruction) const {
|
||||||
|
ASSERT(Matches(instruction));
|
||||||
|
return fn(v, instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* name;
|
||||||
|
opcode_type mask;
|
||||||
|
opcode_type expected;
|
||||||
|
handler_function fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Arm
|
||||||
|
} // namespace Dynarmic
|
|
@ -6,60 +6,25 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <functional>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend/decoder/decoder_detail.h"
|
#include "frontend/decoder/decoder_detail.h"
|
||||||
|
#include "frontend/decoder/matcher.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace Arm {
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
struct Thumb16Matcher {
|
using Thumb16Matcher = Matcher<Visitor, u16>;
|
||||||
using CallRetT = mp::return_type_t<decltype(&Visitor::thumb16_UDF)>;
|
|
||||||
|
|
||||||
Thumb16Matcher(const char* const name, u16 mask, u16 expect, std::function<CallRetT(Visitor&, u16)> fn)
|
|
||||||
: name(name), mask(mask), expect(expect), fn(fn) {}
|
|
||||||
|
|
||||||
/// Gets the name of this type of instruction.
|
|
||||||
const char* GetName() const {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests to see if the instruction is this type of instruction.
|
|
||||||
* @param instruction The instruction to test
|
|
||||||
* @returns true if the instruction is
|
|
||||||
*/
|
|
||||||
bool Matches(u16 instruction) const {
|
|
||||||
return (instruction & mask) == expect;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the corresponding instruction handler on visitor for this type of instruction.
|
|
||||||
* @param v The visitor to use
|
|
||||||
* @param instruction The instruction to decode.
|
|
||||||
*/
|
|
||||||
CallRetT call(Visitor& v, u16 instruction) const {
|
|
||||||
ASSERT(Matches(instruction));
|
|
||||||
return fn(v, instruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const char* name;
|
|
||||||
u16 mask, expect;
|
|
||||||
std::function<CallRetT(Visitor&, u16)> fn;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
boost::optional<const Thumb16Matcher<V>&> DecodeThumb16(u16 instruction) {
|
boost::optional<const Thumb16Matcher<V>&> DecodeThumb16(u16 instruction) {
|
||||||
const static std::vector<Thumb16Matcher<V>> table = {
|
const static std::vector<Thumb16Matcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) detail::detail<Thumb16Matcher, u16, 16>::GetMatcher<decltype(fn)>(fn, name, bitstring)
|
#define INST(fn, name, bitstring) detail::detail<Thumb16Matcher<V>>::GetMatcher(fn, name, bitstring)
|
||||||
|
|
||||||
// Shift (immediate), add, subtract, move and compare instructions
|
// Shift (immediate), add, subtract, move and compare instructions
|
||||||
INST(&V::thumb16_LSL_imm, "LSL (imm)", "00000vvvvvmmmddd"),
|
INST(&V::thumb16_LSL_imm, "LSL (imm)", "00000vvvvvmmmddd"),
|
||||||
|
|
|
@ -6,60 +6,25 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <functional>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend/decoder/decoder_detail.h"
|
#include "frontend/decoder/decoder_detail.h"
|
||||||
|
#include "frontend/decoder/matcher.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace Arm {
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
struct Thumb32Matcher {
|
using Thumb32Matcher = Matcher<Visitor, u32>;
|
||||||
using CallRetT = mp::return_type_t<decltype(&Visitor::thumb32_UDF)>;
|
|
||||||
|
|
||||||
Thumb32Matcher(const char* const name, u32 mask, u32 expect, std::function<CallRetT(Visitor&, u32)> fn)
|
|
||||||
: name(name), mask(mask), expect(expect), fn(fn) {}
|
|
||||||
|
|
||||||
/// Gets the name of this type of instruction.
|
|
||||||
const char* GetName() const {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests to see if the instruction is this type of instruction.
|
|
||||||
* @param instruction The instruction to test
|
|
||||||
* @returns true if the instruction is
|
|
||||||
*/
|
|
||||||
bool Matches(u32 instruction) const {
|
|
||||||
return (instruction & mask) == expect;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the corresponding instruction handler on visitor for this type of instruction.
|
|
||||||
* @param v The visitor to use
|
|
||||||
* @param instruction The instruction to decode.
|
|
||||||
*/
|
|
||||||
CallRetT call(Visitor& v, u32 instruction) const {
|
|
||||||
ASSERT(Matches(instruction));
|
|
||||||
return fn(v, instruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const char* name;
|
|
||||||
u32 mask, expect;
|
|
||||||
std::function<CallRetT(Visitor&, u32)> fn;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
boost::optional<const Thumb32Matcher<V>&> DecodeThumb32(u32 instruction) {
|
boost::optional<const Thumb32Matcher<V>&> DecodeThumb32(u32 instruction) {
|
||||||
const static std::vector<Thumb32Matcher<V>> table = {
|
const static std::vector<Thumb32Matcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) detail::detail<Thumb32Matcher, u32, 32>::GetMatcher<decltype(fn)>(fn, name, bitstring)
|
#define INST(fn, name, bitstring) detail::detail<Thumb32Matcher<V>>::GetMatcher(fn, name, bitstring)
|
||||||
|
|
||||||
// Branch instructions
|
// Branch instructions
|
||||||
INST(&V::thumb32_BL_imm, "BL (imm)", "11110vvvvvvvvvvv11111vvvvvvvvvvv"), // v4T
|
INST(&V::thumb32_BL_imm, "BL (imm)", "11110vvvvvvvvvvv11111vvvvvvvvvvv"), // v4T
|
||||||
|
|
|
@ -6,60 +6,25 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <functional>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend/decoder/decoder_detail.h"
|
#include "frontend/decoder/decoder_detail.h"
|
||||||
|
#include "frontend/decoder/matcher.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace Arm {
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
struct VFP2Matcher {
|
using VFP2Matcher = Matcher<Visitor, u32>;
|
||||||
using CallRetT = mp::return_type_t<decltype(&Visitor::vfp2_VADD)>;
|
|
||||||
|
|
||||||
VFP2Matcher(const char* const name, u32 mask, u32 expect, std::function<CallRetT(Visitor&, u32)> fn)
|
|
||||||
: name(name), mask(mask), expect(expect), fn(fn) {}
|
|
||||||
|
|
||||||
/// Gets the name of this type of instruction.
|
|
||||||
const char* GetName() const {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests to see if the instruction is this type of instruction.
|
|
||||||
* @param instruction The instruction to test
|
|
||||||
* @returns true if the instruction is
|
|
||||||
*/
|
|
||||||
bool Matches(u32 instruction) const {
|
|
||||||
return (instruction & mask) == expect;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the corresponding instruction handler on visitor for this type of instruction.
|
|
||||||
* @param v The visitor to use
|
|
||||||
* @param instruction The instruction to decode.
|
|
||||||
*/
|
|
||||||
CallRetT call(Visitor& v, u32 instruction) const {
|
|
||||||
assert(Matches(instruction));
|
|
||||||
return fn(v, instruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const char* name;
|
|
||||||
u32 mask, expect;
|
|
||||||
std::function<CallRetT(Visitor&, u32)> fn;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
boost::optional<const VFP2Matcher<V>&> DecodeVFP2(u32 instruction) {
|
boost::optional<const VFP2Matcher<V>&> DecodeVFP2(u32 instruction) {
|
||||||
const static std::vector<VFP2Matcher<V>> table = {
|
const static std::vector<VFP2Matcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) detail::detail<VFP2Matcher, u32, 32>::GetMatcher<decltype(fn)>(fn, name, bitstring)
|
#define INST(fn, name, bitstring) detail::detail<VFP2Matcher<V>>::GetMatcher(fn, name, bitstring)
|
||||||
|
|
||||||
// cccc1110________----101-__-0----
|
// cccc1110________----101-__-0----
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace Arm {
|
||||||
|
|
||||||
class DisassemblerVisitor {
|
class DisassemblerVisitor {
|
||||||
public:
|
public:
|
||||||
|
using instruction_return_type = std::string;
|
||||||
|
|
||||||
u32 rotr(u32 x, int shift) {
|
u32 rotr(u32 x, int shift) {
|
||||||
shift &= 31;
|
shift &= 31;
|
||||||
if (!shift) return x;
|
if (!shift) return x;
|
||||||
|
|
|
@ -20,6 +20,8 @@ namespace Arm {
|
||||||
|
|
||||||
class DisassemblerVisitor {
|
class DisassemblerVisitor {
|
||||||
public:
|
public:
|
||||||
|
using instruction_return_type = std::string;
|
||||||
|
|
||||||
std::string thumb16_LSL_imm(Imm5 imm5, Reg m, Reg d) {
|
std::string thumb16_LSL_imm(Imm5 imm5, Reg m, Reg d) {
|
||||||
return fmt::format("lsls {}, {}, #{}", d, m, imm5);
|
return fmt::format("lsls {}, {}, #{}", d, m, imm5);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ enum class ConditionalState {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ArmTranslatorVisitor final {
|
struct ArmTranslatorVisitor final {
|
||||||
|
using instruction_return_type = bool;
|
||||||
|
|
||||||
explicit ArmTranslatorVisitor(IR::LocationDescriptor descriptor) : ir(descriptor) {
|
explicit ArmTranslatorVisitor(IR::LocationDescriptor descriptor) : ir(descriptor) {
|
||||||
ASSERT_MSG(!descriptor.TFlag(), "The processor must be in Arm mode");
|
ASSERT_MSG(!descriptor.TFlag(), "The processor must be in Arm mode");
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace Arm {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct ThumbTranslatorVisitor final {
|
struct ThumbTranslatorVisitor final {
|
||||||
|
using instruction_return_type = bool;
|
||||||
|
|
||||||
explicit ThumbTranslatorVisitor(IR::LocationDescriptor descriptor) : ir(descriptor) {
|
explicit ThumbTranslatorVisitor(IR::LocationDescriptor descriptor) : ir(descriptor) {
|
||||||
ASSERT_MSG(descriptor.TFlag(), "The processor must be in Thumb mode");
|
ASSERT_MSG(descriptor.TFlag(), "The processor must be in Thumb mode");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue