early-access version 1255
This commit is contained in:
167
externals/dynarmic/src/frontend/decoder/decoder_detail.h
vendored
Executable file
167
externals/dynarmic/src/frontend/decoder/decoder_detail.h
vendored
Executable file
@@ -0,0 +1,167 @@
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
|
||||
#include <mp/traits/function_info.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_util.h"
|
||||
|
||||
namespace Dynarmic::Decoder {
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Helper functions for the decoders.
|
||||
*
|
||||
* @tparam MatcherT The type of the Matcher to use.
|
||||
*/
|
||||
template<class MatcherT>
|
||||
struct detail {
|
||||
private:
|
||||
using opcode_type = typename MatcherT::opcode_type;
|
||||
using visitor_type = typename MatcherT::visitor_type;
|
||||
|
||||
static constexpr size_t opcode_bitsize = Common::BitSize<opcode_type>();
|
||||
|
||||
/**
|
||||
* 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 '1' in a bitstring indicates that a one must be present at that bit position.
|
||||
*/
|
||||
static constexpr auto GetMaskAndExpect(const char* const bitstring) {
|
||||
const auto one = static_cast<opcode_type>(1);
|
||||
opcode_type mask = 0, expect = 0;
|
||||
for (size_t i = 0; i < opcode_bitsize; i++) {
|
||||
const size_t bit_position = opcode_bitsize - i - 1;
|
||||
switch (bitstring[i]) {
|
||||
case '0':
|
||||
mask |= one << bit_position;
|
||||
break;
|
||||
case '1':
|
||||
expect |= one << bit_position;
|
||||
mask |= one << bit_position;
|
||||
break;
|
||||
default:
|
||||
// Ignore
|
||||
break;
|
||||
}
|
||||
}
|
||||
return std::make_tuple(mask, expect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the masks and shifts for each argument.
|
||||
* A '-' in a bitstring indicates that we don't care about that value.
|
||||
* An argument is specified by a continuous string of the same character.
|
||||
*/
|
||||
template<size_t N>
|
||||
static auto GetArgInfo(const char* const bitstring) {
|
||||
const auto one = static_cast<opcode_type>(1);
|
||||
std::array<opcode_type, N> masks = {};
|
||||
std::array<size_t, N> shifts = {};
|
||||
size_t arg_index = 0;
|
||||
char ch = 0;
|
||||
|
||||
for (size_t i = 0; i < opcode_bitsize; i++) {
|
||||
const size_t bit_position = opcode_bitsize - i - 1;
|
||||
|
||||
if (bitstring[i] == '0' || bitstring[i] == '1' || bitstring[i] == '-') {
|
||||
if (ch != 0) {
|
||||
ch = 0;
|
||||
arg_index++;
|
||||
}
|
||||
} else {
|
||||
if (ch == 0) {
|
||||
ch = bitstring[i];
|
||||
} else if (ch != bitstring[i]) {
|
||||
ch = bitstring[i];
|
||||
arg_index++;
|
||||
}
|
||||
|
||||
ASSERT(arg_index < N);
|
||||
masks[arg_index] |= one << bit_position;
|
||||
shifts[arg_index] = bit_position;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(std::all_of(masks.begin(), masks.end(), [](auto m){ return m != 0; }));
|
||||
|
||||
return std::make_tuple(masks, shifts);
|
||||
}
|
||||
|
||||
/**
|
||||
* This struct's Make member function generates a lambda which decodes an instruction based on
|
||||
* the provided arg_masks and arg_shifts. The Visitor member function to call is provided as a
|
||||
* template argument.
|
||||
*/
|
||||
template<typename FnT>
|
||||
struct VisitorCaller;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4800) // forcing value to bool 'true' or 'false' (performance warning)
|
||||
#endif
|
||||
template<typename Visitor, typename ...Args, typename CallRetT>
|
||||
struct VisitorCaller<CallRetT(Visitor::*)(Args...)> {
|
||||
template<size_t ...iota>
|
||||
static auto Make(std::integer_sequence<size_t, iota...>,
|
||||
CallRetT (Visitor::* const fn)(Args...),
|
||||
const std::array<opcode_type, sizeof...(iota)> arg_masks,
|
||||
const std::array<size_t, sizeof...(iota)> arg_shifts) {
|
||||
static_assert(std::is_same_v<visitor_type, Visitor>, "Member function is not from Matcher's Visitor");
|
||||
return [fn, arg_masks, arg_shifts](Visitor& v, opcode_type instruction) {
|
||||
(void)instruction;
|
||||
(void)arg_masks;
|
||||
(void)arg_shifts;
|
||||
return (v.*fn)(static_cast<Args>((instruction & arg_masks[iota]) >> arg_shifts[iota])...);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Visitor, typename ...Args, typename CallRetT>
|
||||
struct VisitorCaller<CallRetT(Visitor::*)(Args...) const> {
|
||||
template<size_t ...iota>
|
||||
static auto Make(std::integer_sequence<size_t, iota...>,
|
||||
CallRetT (Visitor::* const fn)(Args...) const,
|
||||
const std::array<opcode_type, sizeof...(iota)> arg_masks,
|
||||
const std::array<size_t, sizeof...(iota)> arg_shifts) {
|
||||
static_assert(std::is_same_v<visitor_type, const Visitor>, "Member function is not from Matcher's Visitor");
|
||||
return [fn, arg_masks, arg_shifts](const Visitor& v, opcode_type instruction) {
|
||||
(void)instruction;
|
||||
(void)arg_masks;
|
||||
(void)arg_shifts;
|
||||
return (v.*fn)(static_cast<Args>((instruction & arg_masks[iota]) >> arg_shifts[iota])...);
|
||||
};
|
||||
}
|
||||
};
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a matcher that can match and parse instructions based on bitstring.
|
||||
* See also: GetMaskAndExpect and GetArgInfo for format of bitstring.
|
||||
*/
|
||||
template<typename FnT>
|
||||
static auto GetMatcher(FnT fn, const char* const name, const char* const bitstring) {
|
||||
constexpr size_t args_count = mp::parameter_count_v<FnT>;
|
||||
using Iota = std::make_index_sequence<args_count>;
|
||||
|
||||
const auto [mask, expect] = GetMaskAndExpect(bitstring);
|
||||
const auto [arg_masks, arg_shifts] = GetArgInfo<args_count>(bitstring);
|
||||
const auto proxy_fn = VisitorCaller<FnT>::Make(Iota(), fn, arg_masks, arg_shifts);
|
||||
|
||||
return MatcherT(name, mask, expect, proxy_fn);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace Dynarmic::Decoder
|
76
externals/dynarmic/src/frontend/decoder/matcher.h
vendored
Executable file
76
externals/dynarmic/src/frontend/decoder/matcher.h
vendored
Executable file
@@ -0,0 +1,76 @@
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "common/assert.h"
|
||||
|
||||
namespace Dynarmic::Decoder {
|
||||
|
||||
/**
|
||||
* 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 visitor_type = Visitor;
|
||||
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 Dynarmic::Decoder
|
Reference in New Issue
Block a user