mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
New bitsets (experimental)
This commit is contained in:
parent
71441819e5
commit
46735d6b3d
@ -1,269 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// Small bitset for enum class types with available values [0, BitSize).
|
||||
// T must be either enum type or convertible to (registered with via simple_t<T>).
|
||||
// Internal representation is single value of type T.
|
||||
template<typename T, std::size_t BitSize = sizeof(T) * CHAR_BIT>
|
||||
struct bitset_t
|
||||
{
|
||||
using type = simple_t<T>;
|
||||
using under = std::underlying_type_t<type>;
|
||||
enum class raw_type : under {};
|
||||
|
||||
static constexpr auto bitsize = BitSize;
|
||||
|
||||
bitset_t() = default;
|
||||
|
||||
constexpr bitset_t(type _enum_const)
|
||||
: m_value(static_cast<type>(shift(_enum_const)))
|
||||
{
|
||||
}
|
||||
|
||||
constexpr bitset_t(raw_type raw_value)
|
||||
: m_value(static_cast<T>(static_cast<under>(raw_value)))
|
||||
{
|
||||
}
|
||||
|
||||
// Get underlying value
|
||||
constexpr under _value() const
|
||||
{
|
||||
return static_cast<under>(m_value);
|
||||
}
|
||||
|
||||
explicit constexpr operator bool() const
|
||||
{
|
||||
return _value() ? true : false;
|
||||
}
|
||||
|
||||
bitset_t& operator +=(bitset_t rhs)
|
||||
{
|
||||
return *this = static_cast<raw_type>(_value() | rhs._value());
|
||||
}
|
||||
|
||||
bitset_t& operator -=(bitset_t rhs)
|
||||
{
|
||||
return *this = static_cast<raw_type>(_value() & ~rhs._value());
|
||||
}
|
||||
|
||||
bitset_t& operator &=(bitset_t rhs)
|
||||
{
|
||||
return *this = static_cast<raw_type>(_value() & rhs._value());
|
||||
}
|
||||
|
||||
bitset_t& operator ^=(bitset_t rhs)
|
||||
{
|
||||
return *this = static_cast<raw_type>(_value() ^ rhs._value());
|
||||
}
|
||||
|
||||
friend constexpr bitset_t operator +(bitset_t lhs, bitset_t rhs)
|
||||
{
|
||||
return static_cast<raw_type>(lhs._value() | rhs._value());
|
||||
}
|
||||
|
||||
friend constexpr bitset_t operator -(bitset_t lhs, bitset_t rhs)
|
||||
{
|
||||
return static_cast<raw_type>(lhs._value() & ~rhs._value());
|
||||
}
|
||||
|
||||
friend constexpr bitset_t operator &(bitset_t lhs, bitset_t rhs)
|
||||
{
|
||||
return static_cast<raw_type>(lhs._value() & rhs._value());
|
||||
}
|
||||
|
||||
friend constexpr bitset_t operator ^(bitset_t lhs, bitset_t rhs)
|
||||
{
|
||||
return static_cast<raw_type>(lhs._value() ^ rhs._value());
|
||||
}
|
||||
|
||||
bool test(bitset_t rhs) const
|
||||
{
|
||||
const under v = _value();
|
||||
const under s = rhs._value();
|
||||
return (v & s) != 0;
|
||||
}
|
||||
|
||||
bool test_and_set(bitset_t rhs)
|
||||
{
|
||||
const under v = _value();
|
||||
const under s = rhs._value();
|
||||
*this = static_cast<raw_type>(v | s);
|
||||
return (v & s) != 0;
|
||||
}
|
||||
|
||||
bool test_and_reset(bitset_t rhs)
|
||||
{
|
||||
const under v = _value();
|
||||
const under s = rhs._value();
|
||||
*this = static_cast<raw_type>(v & ~s);
|
||||
return (v & s) != 0;
|
||||
}
|
||||
|
||||
bool test_and_complement(bitset_t rhs)
|
||||
{
|
||||
const under v = _value();
|
||||
const under s = rhs._value();
|
||||
*this = static_cast<raw_type>(v ^ s);
|
||||
return (v & s) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr under shift(const T& value)
|
||||
{
|
||||
return static_cast<under>(value) < BitSize ? static_cast<under>(1) << static_cast<under>(value) : throw value;
|
||||
}
|
||||
|
||||
T m_value;
|
||||
};
|
||||
|
||||
template<typename T, typename RT = T>
|
||||
constexpr RT make_bitset()
|
||||
{
|
||||
return RT{};
|
||||
}
|
||||
|
||||
// Fold enum constants into bitset_t<> (must be implemented with constexpr initializer_list constructor instead)
|
||||
template<typename T = void, typename Arg, typename... Args, typename RT = std::conditional_t<std::is_void<T>::value, bitset_t<Arg>, T>>
|
||||
constexpr RT make_bitset(Arg&& _enum_const, Args&&... args)
|
||||
{
|
||||
return RT{ std::forward<Arg>(_enum_const) } + make_bitset<RT>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T, typename CT>
|
||||
struct atomic_add<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
|
||||
{
|
||||
using under = typename bitset_t<T>::under;
|
||||
using raw_type = typename bitset_t<T>::raw_type;
|
||||
|
||||
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
|
||||
{
|
||||
return static_cast<raw_type>(atomic_storage<under>::fetch_or(reinterpret_cast<under&>(left), right._value()));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
|
||||
{
|
||||
return static_cast<raw_type>(atomic_storage<under>::or_fetch(reinterpret_cast<under&>(left), right._value()));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T, typename CT>
|
||||
struct atomic_sub<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
|
||||
{
|
||||
using under = typename bitset_t<T>::under;
|
||||
using raw_type = typename bitset_t<T>::raw_type;
|
||||
|
||||
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
|
||||
{
|
||||
return static_cast<raw_type>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), ~right._value()));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
|
||||
{
|
||||
return static_cast<raw_type>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), ~right._value()));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T, typename CT>
|
||||
struct atomic_and<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
|
||||
{
|
||||
using under = typename bitset_t<T>::under;
|
||||
using raw_type = typename bitset_t<T>::raw_type;
|
||||
|
||||
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
|
||||
{
|
||||
return static_cast<raw_type>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), right._value()));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
|
||||
{
|
||||
return static_cast<raw_type>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), right._value()));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T, typename CT>
|
||||
struct atomic_xor<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
|
||||
{
|
||||
using under = typename bitset_t<T>::under;
|
||||
using raw_type = typename bitset_t<T>::raw_type;
|
||||
|
||||
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
|
||||
{
|
||||
return static_cast<raw_type>(atomic_storage<under>::fetch_xor(reinterpret_cast<under&>(left), right._value()));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
|
||||
{
|
||||
return static_cast<raw_type>(atomic_storage<under>::xor_fetch(reinterpret_cast<under&>(left), right._value()));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_test_and_set<bitset_t<T>, T, std::enable_if_t<std::is_enum<T>::value>>
|
||||
{
|
||||
using under = typename bitset_t<T>::under;
|
||||
|
||||
static inline bool _op(bitset_t<T>& left, const T& value)
|
||||
{
|
||||
return atomic_storage<under>::bts(reinterpret_cast<under&>(left), static_cast<uint>(value));
|
||||
}
|
||||
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_test_and_reset<bitset_t<T>, T, std::enable_if_t<std::is_enum<T>::value>>
|
||||
{
|
||||
using under = typename bitset_t<T>::under;
|
||||
|
||||
static inline bool _op(bitset_t<T>& left, const T& value)
|
||||
{
|
||||
return atomic_storage<under>::btr(reinterpret_cast<under&>(left), static_cast<uint>(value));
|
||||
}
|
||||
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_test_and_complement<bitset_t<T>, T, std::enable_if_t<std::is_enum<T>::value>>
|
||||
{
|
||||
using under = typename bitset_t<T>::under;
|
||||
|
||||
static inline bool _op(bitset_t<T>& left, const T& value)
|
||||
{
|
||||
return atomic_storage<under>::btc(reinterpret_cast<under&>(left), static_cast<uint>(value));
|
||||
}
|
||||
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename T, std::size_t BitSize>
|
||||
struct fmt_unveil<bitset_t<T, BitSize>, void>
|
||||
{
|
||||
using type = typename bitset_t<T, BitSize>::raw_type;
|
||||
|
||||
static inline auto get(const bitset_t<T, BitSize>& value)
|
||||
{
|
||||
return fmt_unveil<type>::get(static_cast<type>(value._value()));
|
||||
}
|
||||
};
|
@ -630,7 +630,7 @@ void fs::file::xfail() const
|
||||
throw fmt::exception("Unexpected fs::error %s", g_tls_error);
|
||||
}
|
||||
|
||||
bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
|
||||
bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
|
||||
{
|
||||
if (auto device = get_virtual_device(path))
|
||||
{
|
||||
@ -645,25 +645,25 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD access = 0;
|
||||
if (mode & fs::read) access |= GENERIC_READ;
|
||||
if (mode & fs::write) access |= mode & fs::append ? FILE_APPEND_DATA : GENERIC_WRITE;
|
||||
if (test(mode & fs::read)) access |= GENERIC_READ;
|
||||
if (test(mode & fs::write)) access |= test(mode & fs::append) ? FILE_APPEND_DATA : GENERIC_WRITE;
|
||||
|
||||
DWORD disp = 0;
|
||||
if (mode & fs::create)
|
||||
if (test(mode & fs::create))
|
||||
{
|
||||
disp =
|
||||
mode & fs::excl ? CREATE_NEW :
|
||||
mode & fs::trunc ? CREATE_ALWAYS : OPEN_ALWAYS;
|
||||
test(mode & fs::excl) ? CREATE_NEW :
|
||||
test(mode & fs::trunc) ? CREATE_ALWAYS : OPEN_ALWAYS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode & fs::excl)
|
||||
if (test(mode & fs::excl))
|
||||
{
|
||||
g_tls_error = error::inval;
|
||||
return false;
|
||||
}
|
||||
|
||||
disp = mode & fs::trunc ? TRUNCATE_EXISTING : OPEN_EXISTING;
|
||||
disp = test(mode & fs::trunc) ? TRUNCATE_EXISTING : OPEN_EXISTING;
|
||||
}
|
||||
|
||||
const HANDLE handle = CreateFileW(to_wchar(path).get(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
@ -801,14 +801,14 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
|
||||
#else
|
||||
int flags = 0;
|
||||
|
||||
if (mode & fs::read && mode & fs::write) flags |= O_RDWR;
|
||||
else if (mode & fs::read) flags |= O_RDONLY;
|
||||
else if (mode & fs::write) flags |= O_WRONLY;
|
||||
if (test(mode & fs::read) && test(mode & fs::write)) flags |= O_RDWR;
|
||||
else if (test(mode & fs::read)) flags |= O_RDONLY;
|
||||
else if (test(mode & fs::write)) flags |= O_WRONLY;
|
||||
|
||||
if (mode & fs::append) flags |= O_APPEND;
|
||||
if (mode & fs::create) flags |= O_CREAT;
|
||||
if (mode & fs::trunc) flags |= O_TRUNC;
|
||||
if (mode & fs::excl) flags |= O_EXCL;
|
||||
if (test(mode & fs::append)) flags |= O_APPEND;
|
||||
if (test(mode & fs::create)) flags |= O_CREAT;
|
||||
if (test(mode & fs::trunc)) flags |= O_TRUNC;
|
||||
if (test(mode & fs::excl)) flags |= O_EXCL;
|
||||
|
||||
const int fd = ::open(path.c_str(), flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
|
||||
|
@ -6,12 +6,12 @@
|
||||
#include <type_traits>
|
||||
|
||||
#include "types.h"
|
||||
#include "BitSet.h"
|
||||
#include "bit_set.h"
|
||||
|
||||
namespace fs
|
||||
{
|
||||
// File open mode flags
|
||||
enum struct open_mode : u32
|
||||
enum class open_mode : u32
|
||||
{
|
||||
read,
|
||||
write,
|
||||
@ -19,16 +19,18 @@ namespace fs
|
||||
create,
|
||||
trunc,
|
||||
excl,
|
||||
|
||||
__bitset_enum_max
|
||||
};
|
||||
|
||||
constexpr bitset_t<open_mode> read = open_mode::read; // Enable reading
|
||||
constexpr bitset_t<open_mode> write = open_mode::write; // Enable writing
|
||||
constexpr bitset_t<open_mode> append = open_mode::append; // Always append to the end of the file
|
||||
constexpr bitset_t<open_mode> create = open_mode::create; // Create file if it doesn't exist
|
||||
constexpr bitset_t<open_mode> trunc = open_mode::trunc; // Clear opened file if it's not empty
|
||||
constexpr bitset_t<open_mode> excl = open_mode::excl; // Failure if the file already exists (used with `create`)
|
||||
constexpr auto read = +open_mode::read; // Enable reading
|
||||
constexpr auto write = +open_mode::write; // Enable writing
|
||||
constexpr auto append = +open_mode::append; // Always append to the end of the file
|
||||
constexpr auto create = +open_mode::create; // Create file if it doesn't exist
|
||||
constexpr auto trunc = +open_mode::trunc; // Clear opened file if it's not empty
|
||||
constexpr auto excl = +open_mode::excl; // Failure if the file already exists (used with `create`)
|
||||
|
||||
constexpr bitset_t<open_mode> rewrite = write + create + trunc;
|
||||
constexpr auto rewrite = open_mode::write + open_mode::create + open_mode::trunc;
|
||||
|
||||
// File seek mode
|
||||
enum class seek_mode : u32
|
||||
@ -93,7 +95,7 @@ namespace fs
|
||||
virtual bool remove(const std::string& path) = 0;
|
||||
virtual bool trunc(const std::string& path, u64 length) = 0;
|
||||
|
||||
virtual std::unique_ptr<file_base> open(const std::string& path, bitset_t<open_mode> mode) = 0;
|
||||
virtual std::unique_ptr<file_base> open(const std::string& path, bs_t<open_mode> mode) = 0;
|
||||
virtual std::unique_ptr<dir_base> open_dir(const std::string& path) = 0;
|
||||
};
|
||||
|
||||
@ -151,13 +153,13 @@ namespace fs
|
||||
file() = default;
|
||||
|
||||
// Open file with specified mode
|
||||
explicit file(const std::string& path, bitset_t<open_mode> mode = ::fs::read)
|
||||
explicit file(const std::string& path, bs_t<open_mode> mode = ::fs::read)
|
||||
{
|
||||
open(path, mode);
|
||||
}
|
||||
|
||||
// Open file with specified mode
|
||||
bool open(const std::string& path, bitset_t<open_mode> mode = ::fs::read);
|
||||
bool open(const std::string& path, bs_t<open_mode> mode = ::fs::read);
|
||||
|
||||
// Open memory for read
|
||||
explicit file(const void* ptr, std::size_t size);
|
||||
|
@ -146,6 +146,32 @@ struct fmt_class_string
|
||||
fmt_class_string<std::underlying_type_t<T>>::format(out, static_cast<u64>(value));
|
||||
}
|
||||
|
||||
// Helper function (bitset formatting)
|
||||
static SAFE_BUFFERS FORCE_INLINE void format_bitset(std::string& out, u64 arg, const char* prefix, const char* delim, const char* suffix, void(*fmt)(std::string&, u64))
|
||||
{
|
||||
// Start from raw value
|
||||
fmt_class_string<u64>::format(out, arg);
|
||||
|
||||
out += prefix;
|
||||
|
||||
for (u64 i = 0; i < 64; i++)
|
||||
{
|
||||
const u64 mask = 1ull << i;
|
||||
|
||||
if (arg & mask)
|
||||
{
|
||||
fmt(out, i);
|
||||
|
||||
if (arg > mask)
|
||||
{
|
||||
out += delim;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out += suffix;
|
||||
}
|
||||
|
||||
// Helper constant (may be used in format_enum as lambda return value)
|
||||
static constexpr const char* unknown = nullptr;
|
||||
};
|
||||
|
636
Utilities/bit_set.h
Normal file
636
Utilities/bit_set.h
Normal file
@ -0,0 +1,636 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
This header helps to extend scoped enum types (enum class) in two possible ways:
|
||||
1) Enabling bitwise operators for enums
|
||||
2) Advanced bs_t<> template (this converts enum type to another "bitset" enum type)
|
||||
|
||||
To enable bitwise operators, enum scope must contain `__bitwise_ops` entry.
|
||||
|
||||
enum class flags
|
||||
{
|
||||
__bitwise_ops, // Not essential, but recommended to put it first
|
||||
|
||||
flag1 = 1 << 0,
|
||||
flag2 = 1 << 1,
|
||||
};
|
||||
|
||||
Examples:
|
||||
`flags::flag1 | flags::flag2` - bitwise OR
|
||||
`flags::flag1 & flags::flag2` - bitwise AND
|
||||
`flags::flag1 ^ flags::flag2` - bitwise XOR
|
||||
`~flags::flag1` - bitwise NEG
|
||||
|
||||
To enable bs_t<> template, enum scope must contain `__bitset_enum_max` entry.
|
||||
|
||||
enum class flagzz : u32
|
||||
{
|
||||
flag1, // Bit indices start from zero
|
||||
flag2,
|
||||
|
||||
__bitset_enum_max // It must be the last value
|
||||
};
|
||||
|
||||
Now some operators are enabled for two enum types: `flagzz` and `bs_t<flagzz>`.
|
||||
These are very different from previously described bitwise operators.
|
||||
|
||||
Examples:
|
||||
`+flagzz::flag1` - unary `+` operator convert flagzz value to bs_t<flagzz>
|
||||
`flagzz::flag1 + flagzz::flag2` - bitset union
|
||||
`flagzz::flag1 - flagzz::flag2` - bitset difference
|
||||
Intersection (&) and symmetric difference (^) is also available.
|
||||
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// Helper template
|
||||
template<typename T>
|
||||
struct bs_base
|
||||
{
|
||||
// Underlying type
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
// Actual bitset type
|
||||
enum class type : under
|
||||
{
|
||||
null = 0, // Empty bitset
|
||||
|
||||
__bitset_set_type = 0 // SFINAE marker
|
||||
};
|
||||
|
||||
static constexpr std::size_t bitmax = sizeof(T) * CHAR_BIT;
|
||||
static constexpr std::size_t bitsize = static_cast<under>(T::__bitset_enum_max);
|
||||
|
||||
static_assert(std::is_enum<T>::value, "bs_t<> error: invalid type (must be enum)");
|
||||
static_assert(!bitsize || bitsize <= bitmax, "bs_t<> error: invalid __bitset_enum_max");
|
||||
|
||||
// Helper function
|
||||
static constexpr under shift(T value)
|
||||
{
|
||||
return static_cast<under>(1) << static_cast<under>(value);
|
||||
}
|
||||
|
||||
friend type& operator +=(type& lhs, type rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) |= static_cast<under>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator -=(type& lhs, type rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) &= ~static_cast<under>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator &=(type& lhs, type rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) &= static_cast<under>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator ^=(type& lhs, type rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) ^= static_cast<under>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator +=(type& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) |= shift(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator -=(type& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) &= ~shift(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator &=(type& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) &= shift(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator ^=(type& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) ^= shift(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend constexpr type operator +(type lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) | static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator -(type lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) & ~static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator &(type lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) & static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator ^(type lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) ^ static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator &(type lhs, T rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) & shift(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator ^(type lhs, T rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) ^ shift(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator &(T lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(shift(lhs) & static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator ^(T lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(shift(lhs) ^ static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr bool operator ==(T lhs, type rhs)
|
||||
{
|
||||
return shift(lhs) == rhs;
|
||||
}
|
||||
|
||||
friend constexpr bool operator ==(type lhs, T rhs)
|
||||
{
|
||||
return lhs == shift(rhs);
|
||||
}
|
||||
|
||||
friend constexpr bool operator !=(T lhs, type rhs)
|
||||
{
|
||||
return shift(lhs) != rhs;
|
||||
}
|
||||
|
||||
friend constexpr bool operator !=(type lhs, T rhs)
|
||||
{
|
||||
return lhs != shift(rhs);
|
||||
}
|
||||
|
||||
friend constexpr bool test(type value)
|
||||
{
|
||||
return static_cast<under>(value) != 0;
|
||||
}
|
||||
|
||||
friend constexpr bool test(type lhs, type rhs)
|
||||
{
|
||||
return (static_cast<under>(lhs) & static_cast<under>(rhs)) != 0;
|
||||
}
|
||||
|
||||
friend constexpr bool test(type lhs, T rhs)
|
||||
{
|
||||
return (static_cast<under>(lhs) & shift(rhs)) != 0;
|
||||
}
|
||||
|
||||
friend constexpr bool test(T lhs, type rhs)
|
||||
{
|
||||
return (shift(lhs) & static_cast<under>(rhs)) != 0;
|
||||
}
|
||||
|
||||
friend constexpr bool test_and_set(type& lhs, type rhs)
|
||||
{
|
||||
return test_and_set(reinterpret_cast<under&>(lhs), static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr bool test_and_set(type& lhs, T rhs)
|
||||
{
|
||||
return test_and_set(reinterpret_cast<under&>(lhs), shift(rhs));
|
||||
}
|
||||
|
||||
friend constexpr bool test_and_reset(type& lhs, type rhs)
|
||||
{
|
||||
return test_and_reset(reinterpret_cast<under&>(lhs), static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr bool test_and_reset(type& lhs, T rhs)
|
||||
{
|
||||
return test_and_reset(reinterpret_cast<under&>(lhs), shift(rhs));
|
||||
}
|
||||
|
||||
friend constexpr bool test_and_complement(type& lhs, type rhs)
|
||||
{
|
||||
return test_and_complement(reinterpret_cast<under&>(lhs), static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr bool test_and_complement(type& lhs, T rhs)
|
||||
{
|
||||
return test_and_complement(reinterpret_cast<under&>(lhs), shift(rhs));
|
||||
}
|
||||
};
|
||||
|
||||
// Bitset type for enum class with available bits [0, T::__bitset_enum_max)
|
||||
template<typename T>
|
||||
using bs_t = typename bs_base<T>::type;
|
||||
|
||||
// Unary '+' operator: promote plain enum value to bitset value
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator +(T value)
|
||||
{
|
||||
return static_cast<bs_t<T>>(bs_base<T>::shift(value));
|
||||
}
|
||||
|
||||
// Binary '+' operator: bitset union
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator +(T lhs, T rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(bs_base<T>::shift(lhs) | bs_base<T>::shift(rhs));
|
||||
}
|
||||
|
||||
// Binary '+' operator: bitset union
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator +(typename bs_base<T>::type lhs, T rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(static_cast<typename bs_base<T>::under>(lhs) | bs_base<T>::shift(rhs));
|
||||
}
|
||||
|
||||
// Binary '+' operator: bitset union
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator +(T lhs, typename bs_base<T>::type rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(bs_base<T>::shift(lhs) | static_cast<typename bs_base<T>::under>(rhs));
|
||||
}
|
||||
|
||||
// Binary '-' operator: bitset difference
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator -(T lhs, T rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(bs_base<T>::shift(lhs) & ~bs_base<T>::shift(rhs));
|
||||
}
|
||||
|
||||
// Binary '-' operator: bitset difference
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator -(typename bs_base<T>::type lhs, T rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(static_cast<typename bs_base<T>::under>(lhs) & ~bs_base<T>::shift(rhs));
|
||||
}
|
||||
|
||||
// Binary '-' operator: bitset difference
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator -(T lhs, typename bs_base<T>::type rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(bs_base<T>::shift(lhs) & ~static_cast<typename bs_base<T>::under>(rhs));
|
||||
}
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_add<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bs_t<T> op1(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::fetch_or(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bs_t<T> op2(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::or_fetch(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_sub<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bs_t<T> op1(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), ~bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bs_t<T> op2(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), ~bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_and<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bs_t<T> op1(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bs_t<T> op2(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_xor<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bs_t<T> op1(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::fetch_xor(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bs_t<T> op2(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::xor_fetch(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_add<T, T, void_t<decltype(T::__bitset_set_type)>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_or(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::or_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_sub<T, T, void_t<decltype(T::__bitset_set_type)>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), ~static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), ~static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_and<T, T, void_t<decltype(T::__bitset_set_type)>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_xor<T, T, void_t<decltype(T::__bitset_set_type)>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_xor(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::xor_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_test_and_set<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bool _op(bs_t<T>& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::bts(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value)));
|
||||
}
|
||||
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_test_and_reset<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bool _op(bs_t<T>& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::btr(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value)));
|
||||
}
|
||||
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_test_and_complement<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bool _op(bs_t<T>& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::btc(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value)));
|
||||
}
|
||||
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
// Binary '|' operator: bitwise OR
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr T operator |(T lhs, T rhs)
|
||||
{
|
||||
return static_cast<T>(std::underlying_type_t<T>(lhs) | std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
// Binary '&' operator: bitwise AND
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr T operator &(T lhs, T rhs)
|
||||
{
|
||||
return static_cast<T>(std::underlying_type_t<T>(lhs) & std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
// Binary '^' operator: bitwise XOR
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr T operator ^(T lhs, T rhs)
|
||||
{
|
||||
return static_cast<T>(std::underlying_type_t<T>(lhs) ^ std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
// Unary '~' operator: bitwise NEG
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr T operator ~(T value)
|
||||
{
|
||||
return static_cast<T>(~std::underlying_type_t<T>(value));
|
||||
}
|
||||
|
||||
// Bitwise OR assignment
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline T& operator |=(T& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<std::underlying_type_t<T>&>(lhs) |= std::underlying_type_t<T>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// Bitwise AND assignment
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline T& operator &=(T& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<std::underlying_type_t<T>&>(lhs) &= std::underlying_type_t<T>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// Bitwise XOR assignment
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline T& operator ^=(T& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<std::underlying_type_t<T>&>(lhs) ^= std::underlying_type_t<T>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr bool test(T value)
|
||||
{
|
||||
return std::underlying_type_t<T>(value) != 0;
|
||||
}
|
||||
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr bool test(T lhs, T rhs)
|
||||
{
|
||||
return (std::underlying_type_t<T>(lhs) & std::underlying_type_t<T>(rhs)) != 0;
|
||||
}
|
||||
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline bool test_and_set(T& lhs, T rhs)
|
||||
{
|
||||
return test_and_set(reinterpret_cast<std::underlying_type_t<T>&>(lhs), std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline bool test_and_reset(T& lhs, T rhs)
|
||||
{
|
||||
return test_and_reset(reinterpret_cast<std::underlying_type_t<T>&>(lhs), std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline bool test_and_complement(T& lhs, T rhs)
|
||||
{
|
||||
return test_and_complement(reinterpret_cast<std::underlying_type_t<T>&>(lhs), std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct atomic_or<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_or(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::or_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_and<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_xor<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_xor(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::xor_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
@ -21,9 +21,32 @@ void fmt_class_string<cpu_type>::format(std::string& out, u64 arg)
|
||||
}
|
||||
|
||||
template<>
|
||||
void fmt_class_string<bitset_t<cpu_state>::raw_type>::format(std::string& out, u64 arg)
|
||||
void fmt_class_string<cpu_state>::format(std::string& out, u64 arg)
|
||||
{
|
||||
out += "[UNIMPLEMENTED]";
|
||||
format_enum(out, arg, [](cpu_state f)
|
||||
{
|
||||
switch (f)
|
||||
{
|
||||
STR_CASE(cpu_state::stop);
|
||||
STR_CASE(cpu_state::exit);
|
||||
STR_CASE(cpu_state::suspend);
|
||||
STR_CASE(cpu_state::ret);
|
||||
STR_CASE(cpu_state::signal);
|
||||
STR_CASE(cpu_state::dbg_global_pause);
|
||||
STR_CASE(cpu_state::dbg_global_stop);
|
||||
STR_CASE(cpu_state::dbg_pause);
|
||||
STR_CASE(cpu_state::dbg_step);
|
||||
case cpu_state::__bitset_enum_max: break;
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
template<>
|
||||
void fmt_class_string<bs_t<cpu_state>>::format(std::string& out, u64 arg)
|
||||
{
|
||||
format_bitset(out, arg, "[", "|", "]", &fmt_class_string<cpu_state>::format);
|
||||
}
|
||||
|
||||
thread_local cpu_thread* g_tls_current_cpu_thread = nullptr;
|
||||
@ -39,12 +62,12 @@ void cpu_thread::on_task()
|
||||
std::unique_lock<named_thread> lock(*this);
|
||||
|
||||
// Check thread status
|
||||
while (!(state & cpu_state::exit))
|
||||
while (!test(state & cpu_state::exit))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
// check stop status
|
||||
if (!(state & cpu_state::stop))
|
||||
if (!test(state & cpu_state::stop))
|
||||
{
|
||||
if (lock) lock.unlock();
|
||||
|
||||
@ -99,12 +122,12 @@ bool cpu_thread::check_state()
|
||||
{
|
||||
CHECK_EMU_STATUS; // check at least once
|
||||
|
||||
if (state & cpu_state::exit)
|
||||
if (test(state & cpu_state::exit))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!state.test(cpu_state_pause))
|
||||
if (!test(state & cpu_state_pause))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -120,12 +143,12 @@ bool cpu_thread::check_state()
|
||||
|
||||
const auto state_ = state.load();
|
||||
|
||||
if (state_ & make_bitset(cpu_state::ret, cpu_state::stop))
|
||||
if (test(state_, cpu_state::ret + cpu_state::stop))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (state_ & cpu_state::dbg_step)
|
||||
if (test(state_, cpu_state::dbg_step))
|
||||
{
|
||||
state += cpu_state::dbg_pause;
|
||||
state -= cpu_state::dbg_step;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Utilities/Thread.h"
|
||||
#include "../Utilities/BitSet.h"
|
||||
#include "../Utilities/bit_set.h"
|
||||
|
||||
// CPU Thread Type (TODO: probably remove, use id and idm to classify threads)
|
||||
enum class cpu_type : u8
|
||||
@ -12,7 +12,7 @@ enum class cpu_type : u8
|
||||
};
|
||||
|
||||
// CPU Thread State flags (TODO: use u32 once cpu_type is removed)
|
||||
enum struct cpu_state : u16
|
||||
enum class cpu_state : u16
|
||||
{
|
||||
stop, // Thread not running (HLE, initial state)
|
||||
exit, // Irreversible exit
|
||||
@ -24,10 +24,12 @@ enum struct cpu_state : u16
|
||||
dbg_global_stop, // Emulation stopped
|
||||
dbg_pause, // Thread paused
|
||||
dbg_step, // Thread forced to pause after one step (one instruction, etc)
|
||||
|
||||
__bitset_enum_max
|
||||
};
|
||||
|
||||
// CPU Thread State flags: pause state union
|
||||
constexpr bitset_t<cpu_state> cpu_state_pause = make_bitset(cpu_state::suspend, cpu_state::dbg_global_pause, cpu_state::dbg_pause);
|
||||
constexpr bs_t<cpu_state> cpu_state_pause = cpu_state::suspend + cpu_state::dbg_global_pause + cpu_state::dbg_pause;
|
||||
|
||||
class cpu_thread : public named_thread
|
||||
{
|
||||
@ -43,7 +45,7 @@ public:
|
||||
cpu_thread(cpu_type type);
|
||||
|
||||
// Public thread state
|
||||
atomic_t<bitset_t<cpu_state>> state{ cpu_state::stop };
|
||||
atomic_t<bs_t<cpu_state>> state{+cpu_state::stop};
|
||||
|
||||
// Object associated with sleep state, possibly synchronization primitive (mutex, semaphore, etc.)
|
||||
atomic_t<void*> owner{};
|
||||
|
@ -11,9 +11,30 @@ const ppu_decoder<ppu_itype> s_ppu_itype;
|
||||
const ppu_decoder<ppu_iname> s_ppu_iname;
|
||||
|
||||
template<>
|
||||
void fmt_class_string<bitset_t<ppu_attr>::raw_type>::format(std::string& out, u64 arg)
|
||||
void fmt_class_string<ppu_attr>::format(std::string& out, u64 arg)
|
||||
{
|
||||
out += "[UNIMPLEMENTED]";
|
||||
format_enum(out, arg, [](ppu_attr value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case ppu_attr::known_addr: return "known_addr";
|
||||
case ppu_attr::known_size: return "known_size";
|
||||
case ppu_attr::no_return: return "no_return";
|
||||
case ppu_attr::no_size: return "no_size";
|
||||
case ppu_attr::uses_r0: return "uses_r0";
|
||||
case ppu_attr::entry_point: return "entry_point";
|
||||
case ppu_attr::complex_stack: return "complex_stack";
|
||||
case ppu_attr::__bitset_enum_max: break;
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
template<>
|
||||
void fmt_class_string<bs_t<ppu_attr>>::format(std::string& out, u64 arg)
|
||||
{
|
||||
format_bitset(out, arg, "[", ",", "]", &fmt_class_string<ppu_attr>::format);
|
||||
}
|
||||
|
||||
void ppu_validate(const std::string& fname, const std::vector<ppu_function>& funcs, u32 reloc)
|
||||
@ -377,7 +398,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
{
|
||||
for (auto it = funcs.lower_bound(addr), end = funcs.end(); it != end; it++)
|
||||
{
|
||||
if (it->second.attr & ppu_attr::known_addr)
|
||||
if (test(it->second.attr, ppu_attr::known_addr))
|
||||
{
|
||||
return it->first;
|
||||
}
|
||||
@ -682,7 +703,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
}
|
||||
|
||||
// Get function limit
|
||||
const u32 func_end = std::min<u32>(get_limit(func.addr + 1), func.attr & ppu_attr::known_size ? func.addr + func.size : end);
|
||||
const u32 func_end = std::min<u32>(get_limit(func.addr + 1), test(func.attr, ppu_attr::known_size) ? func.addr + func.size : end);
|
||||
|
||||
// Block analysis workload
|
||||
std::vector<std::reference_wrapper<std::pair<const u32, u32>>> block_queue;
|
||||
@ -715,7 +736,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
}
|
||||
|
||||
// TODO: lower priority?
|
||||
if (func.attr & ppu_attr::no_size)
|
||||
if (test(func.attr, ppu_attr::no_size))
|
||||
{
|
||||
// Get next function
|
||||
const auto _next = funcs.lower_bound(func.blocks.crbegin()->first + 1);
|
||||
@ -777,12 +798,12 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
}
|
||||
|
||||
// Add next block if necessary
|
||||
if ((is_call && !pfunc->attr.test(ppu_attr::no_return)) || (type == ppu_itype::BC && (op.bo & 0x14) != 0x14))
|
||||
if ((is_call && !test(pfunc->attr, ppu_attr::no_return)) || (type == ppu_itype::BC && (op.bo & 0x14) != 0x14))
|
||||
{
|
||||
add_block(_ptr.addr());
|
||||
}
|
||||
|
||||
if (op.lk && (target == iaddr || pfunc->attr.test(ppu_attr::no_return)))
|
||||
if (op.lk && (target == iaddr || test(pfunc->attr, ppu_attr::no_return)))
|
||||
{
|
||||
// Nothing
|
||||
}
|
||||
@ -843,11 +864,12 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
if (jt_addr != jt_end && _ptr.addr() == jt_addr)
|
||||
{
|
||||
// Acknowledge jumptable detection failure
|
||||
if (!func.attr.test_and_set(ppu_attr::no_size))
|
||||
if (!test(func.attr, ppu_attr::no_size))
|
||||
{
|
||||
LOG_WARNING(PPU, "[0x%x] Jump table not found! 0x%x-0x%x", func.addr, jt_addr, jt_end);
|
||||
}
|
||||
|
||||
func.attr += ppu_attr::no_size;
|
||||
add_block(iaddr);
|
||||
block_queue.clear();
|
||||
}
|
||||
@ -871,7 +893,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
}
|
||||
|
||||
// Finalization: determine function size
|
||||
if (!func.attr.test(ppu_attr::known_size))
|
||||
if (!test(func.attr, ppu_attr::known_size))
|
||||
{
|
||||
const auto last = func.blocks.crbegin();
|
||||
|
||||
@ -937,7 +959,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
}
|
||||
|
||||
// Finalization: decrease known function size (TODO)
|
||||
if (func.attr & ppu_attr::known_size)
|
||||
if (test(func.attr, ppu_attr::known_size))
|
||||
{
|
||||
const auto last = func.blocks.crbegin();
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "Utilities/BitSet.h"
|
||||
#include "Utilities/bit_set.h"
|
||||
#include "Utilities/BEType.h"
|
||||
|
||||
// PPU Function Attributes
|
||||
@ -16,6 +16,8 @@ enum class ppu_attr : u32
|
||||
uses_r0,
|
||||
entry_point,
|
||||
complex_stack,
|
||||
|
||||
__bitset_enum_max
|
||||
};
|
||||
|
||||
// PPU Function Information
|
||||
@ -24,7 +26,7 @@ struct ppu_function
|
||||
u32 addr = 0;
|
||||
u32 toc = 0;
|
||||
u32 size = 0;
|
||||
bitset_t<ppu_attr> attr{};
|
||||
bs_t<ppu_attr> attr{};
|
||||
|
||||
u32 stack_frame = 0;
|
||||
u32 gate_target = 0;
|
||||
|
@ -79,9 +79,8 @@ std::string ppu_thread::get_name() const
|
||||
std::string ppu_thread::dump() const
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
ret += fmt::format("Type: %s\n", typeid(*this).name());
|
||||
ret += fmt::format("State: 0x%08x\n", state.load());
|
||||
ret += fmt::format("State: %s\n", state.load());
|
||||
ret += fmt::format("Priority: %d\n", prio);
|
||||
|
||||
ret += "\nRegisters:\n=========\n";
|
||||
@ -196,7 +195,7 @@ void ppu_thread::exec_task()
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (UNLIKELY(state.load()))
|
||||
if (UNLIKELY(test(state)))
|
||||
{
|
||||
if (check_state()) return;
|
||||
}
|
||||
@ -228,7 +227,7 @@ void ppu_thread::exec_task()
|
||||
func2 = table[_i._u32[2]];
|
||||
func3 = table[_i._u32[3]];
|
||||
|
||||
if (UNLIKELY(state.load()))
|
||||
if (UNLIKELY(test(state)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -241,8 +240,6 @@ void ppu_thread::exec_task()
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto stop_state = make_bitset(cpu_state::stop, cpu_state::exit, cpu_state::suspend);
|
||||
|
||||
ppu_thread::~ppu_thread()
|
||||
{
|
||||
if (stack_addr)
|
||||
@ -311,7 +308,7 @@ ppu_cmd ppu_thread::cmd_wait()
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (UNLIKELY(state.load()))
|
||||
if (UNLIKELY(test(state)))
|
||||
{
|
||||
if (lock) lock.unlock();
|
||||
|
||||
@ -368,7 +365,7 @@ void ppu_thread::fast_call(u32 addr, u32 rtoc)
|
||||
{
|
||||
exec_task();
|
||||
|
||||
if (gpr[1] != old_stack && !state.test(cpu_state::ret) && !state.test(cpu_state::exit)) // gpr[1] shouldn't change
|
||||
if (gpr[1] != old_stack && !test(state, cpu_state::ret + cpu_state::exit)) // gpr[1] shouldn't change
|
||||
{
|
||||
throw fmt::exception("Stack inconsistency (addr=0x%x, rtoc=0x%x, SP=0x%llx, old=0x%llx)", addr, rtoc, gpr[1], old_stack);
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ Function* PPUTranslator::TranslateToIR(const ppu_function& info, be_t<u32>* bin,
|
||||
m_base_loaded = m_ir->CreateLoad(m_base);
|
||||
|
||||
// Non-volatile registers with special meaning (TODO)
|
||||
if (info.attr & ppu_attr::uses_r0) m_g_gpr[0] = m_ir->CreateConstGEP2_32(nullptr, m_thread, 0, 1 + 0, ".r0g");
|
||||
if (test(info.attr, ppu_attr::uses_r0)) m_g_gpr[0] = m_ir->CreateConstGEP2_32(nullptr, m_thread, 0, 1 + 0, ".r0g");
|
||||
m_g_gpr[1] = m_ir->CreateConstGEP2_32(nullptr, m_thread, 0, 1 + 1, ".spg");
|
||||
m_g_gpr[2] = m_ir->CreateConstGEP2_32(nullptr, m_thread, 0, 1 + 2, ".rtoc");
|
||||
m_g_gpr[13] = m_ir->CreateConstGEP2_32(nullptr, m_thread, 0, 1 + 13, ".tls");
|
||||
|
@ -269,7 +269,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op)
|
||||
|
||||
const u32 old_pc = _spu->pc;
|
||||
|
||||
if (_spu->state.load() && _spu->check_state())
|
||||
if (test(_spu->state) && _spu->check_state())
|
||||
{
|
||||
return 0x2000000 | _spu->pc;
|
||||
}
|
||||
@ -340,12 +340,12 @@ void spu_recompiler::FunctionCall()
|
||||
LOG_ERROR(SPU, "Branch-to-self");
|
||||
}
|
||||
|
||||
while (!_spu->state.load() || !_spu->check_state())
|
||||
while (!test(_spu->state) || !_spu->check_state())
|
||||
{
|
||||
// Proceed recursively
|
||||
spu_recompiler_base::enter(*_spu);
|
||||
|
||||
if (_spu->state & cpu_state::ret)
|
||||
if (test(_spu->state & cpu_state::ret))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -2186,7 +2186,7 @@ void spu_recompiler::BR(spu_opcode_t op)
|
||||
c->mov(*addr, target | 0x2000000);
|
||||
//c->cmp(asmjit::host::dword_ptr(*ls, m_pos), 0x32); // compare instruction opcode with BR-to-self
|
||||
//c->je(labels[target / 4]);
|
||||
c->lock().or_(SPU_OFF_16(state), make_bitset(cpu_state::stop, cpu_state::ret)._value());
|
||||
c->lock().or_(SPU_OFF_16(state), static_cast<u16>(cpu_state::stop + cpu_state::ret));
|
||||
c->jmp(*end);
|
||||
c->unuse(*addr);
|
||||
return;
|
||||
|
@ -213,7 +213,7 @@ void SPUThread::cpu_task()
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!state.load())
|
||||
if (!test(state))
|
||||
{
|
||||
// Read opcode
|
||||
const u32 op = base[pc / 4];
|
||||
@ -599,9 +599,9 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
{
|
||||
if (!channel.try_pop(out))
|
||||
{
|
||||
thread_lock{*this}, thread_ctrl::wait(WRAP_EXPR(state & cpu_state::stop || channel.try_pop(out)));
|
||||
thread_lock{*this}, thread_ctrl::wait(WRAP_EXPR(test(state & cpu_state::stop) || channel.try_pop(out)));
|
||||
|
||||
return !state.test(cpu_state::stop);
|
||||
return !test(state & cpu_state::stop);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -630,7 +630,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
if (state & cpu_state::stop)
|
||||
if (test(state & cpu_state::stop))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -702,14 +702,14 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
if (ch_event_mask & SPU_EVENT_LR)
|
||||
{
|
||||
// register waiter if polling reservation status is required
|
||||
vm::wait_op(last_raddr, 128, WRAP_EXPR(get_events(true) || state & cpu_state::stop));
|
||||
vm::wait_op(last_raddr, 128, WRAP_EXPR(get_events(true) || test(state & cpu_state::stop)));
|
||||
}
|
||||
else
|
||||
{
|
||||
lock.lock();
|
||||
|
||||
// simple waiting loop otherwise
|
||||
while (!get_events(true) && !(state & cpu_state::stop))
|
||||
while (!get_events(true) && !test(state & cpu_state::stop))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
@ -719,7 +719,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
|
||||
ch_event_stat &= ~SPU_EVENT_WAITING;
|
||||
|
||||
if (state & cpu_state::stop)
|
||||
if (test(state & cpu_state::stop))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -759,7 +759,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
if (state & cpu_state::stop)
|
||||
if (test(state & cpu_state::stop))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -966,7 +966,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
if (state & cpu_state::stop)
|
||||
if (test(state & cpu_state::stop))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -1231,7 +1231,7 @@ bool SPUThread::stop_and_signal(u32 code)
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
if (state & cpu_state::stop)
|
||||
if (test(state & cpu_state::stop))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -1272,7 +1272,7 @@ bool SPUThread::stop_and_signal(u32 code)
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
if (state & cpu_state::stop)
|
||||
if (test(state & cpu_state::stop))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ ppu_error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32
|
||||
return CELL_EISDIR;
|
||||
}
|
||||
|
||||
bitset_t<fs::open_mode> open_mode{};
|
||||
bs_t<fs::open_mode> open_mode{};
|
||||
|
||||
switch (flags & CELL_FS_O_ACCMODE)
|
||||
{
|
||||
@ -125,7 +125,7 @@ ppu_error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32
|
||||
open_mode = {}; // error
|
||||
}
|
||||
|
||||
if (!open_mode)
|
||||
if (!test(open_mode))
|
||||
{
|
||||
throw EXCEPTION("Invalid or unimplemented flags (%#o): '%s'", flags, path.get_ptr());
|
||||
}
|
||||
@ -136,7 +136,7 @@ ppu_error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32
|
||||
{
|
||||
sys_fs.error("sys_fs_open('%s'): failed to open file (flags=%#o, mode=%#o)", path.get_ptr(), flags, mode);
|
||||
|
||||
if (open_mode & fs::excl)
|
||||
if (test(open_mode & fs::excl))
|
||||
{
|
||||
return CELL_EEXIST; // approximation
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ void lv2_int_serv_t::join(ppu_thread& ppu, lv2_lock_t lv2_lock)
|
||||
thread->lock_notify();
|
||||
|
||||
// Join thread (TODO)
|
||||
while (!(thread->state & cpu_state::exit))
|
||||
while (!test(thread->state & cpu_state::exit))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
@ -91,7 +91,7 @@ s32 _sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u32 intrthread
|
||||
}
|
||||
|
||||
// If interrupt thread is running, it's already established on another interrupt tag
|
||||
if (!(it->state & cpu_state::stop))
|
||||
if (!test(it->state & cpu_state::stop))
|
||||
{
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ s32 sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr)
|
||||
thread->is_joining = true;
|
||||
|
||||
// join thread
|
||||
while (!(thread->state & cpu_state::exit))
|
||||
while (!test(thread->state & cpu_state::exit))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
|
@ -77,7 +77,7 @@ void ARMv7Thread::cpu_task_main()
|
||||
return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->PC);
|
||||
};
|
||||
|
||||
while (!state.load() || !check_state())
|
||||
while (!test(state) || !check_state())
|
||||
{
|
||||
if (ISET == Thumb)
|
||||
{
|
||||
@ -142,7 +142,7 @@ void ARMv7Thread::fast_call(u32 addr)
|
||||
{
|
||||
cpu_task_main();
|
||||
|
||||
if (SP != old_SP && !state.test(cpu_state::ret) && !state.test(cpu_state::exit)) // SP shouldn't change
|
||||
if (SP != old_SP && !test(state, cpu_state::ret + cpu_state::exit)) // SP shouldn't change
|
||||
{
|
||||
throw fmt::exception("Stack inconsistency (addr=0x%x, SP=0x%x, old=0x%x)", addr, SP, old_SP);
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ void InterpreterDisAsmFrame::ShowAddr(u32 addr)
|
||||
|
||||
wxColour colour;
|
||||
|
||||
if (cpu->state.test(cpu_state_pause) && m_pc == GetPc())
|
||||
if (test(cpu->state & cpu_state_pause) && m_pc == GetPc())
|
||||
{
|
||||
colour = wxColour("Green");
|
||||
}
|
||||
@ -436,7 +436,7 @@ void InterpreterDisAsmFrame::Show_PC(wxCommandEvent& WXUNUSED(event))
|
||||
|
||||
void InterpreterDisAsmFrame::DoRun(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
if (cpu && cpu->state.test(cpu_state_pause))
|
||||
if (cpu && test(cpu->state & cpu_state_pause))
|
||||
{
|
||||
cpu->state -= cpu_state::dbg_pause;
|
||||
(*cpu)->lock_notify();
|
||||
@ -455,11 +455,11 @@ void InterpreterDisAsmFrame::DoStep(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
if (cpu)
|
||||
{
|
||||
if (cpu->state.atomic_op([](bitset_t<cpu_state>& state) -> bool
|
||||
if (test(cpu_state::dbg_pause, cpu->state.fetch_op([](bs_t<cpu_state>& state)
|
||||
{
|
||||
state += cpu_state::dbg_step;
|
||||
return state.test_and_reset(cpu_state::dbg_pause);
|
||||
}))
|
||||
state -= cpu_state::dbg_pause;
|
||||
})))
|
||||
{
|
||||
(*cpu)->lock_notify();
|
||||
}
|
||||
|
@ -386,7 +386,7 @@
|
||||
<ClInclude Include="..\Utilities\AutoPause.h" />
|
||||
<ClInclude Include="..\Utilities\BEType.h" />
|
||||
<ClInclude Include="..\Utilities\BitField.h" />
|
||||
<ClInclude Include="..\Utilities\BitSet.h" />
|
||||
<ClInclude Include="..\Utilities\bit_set.h" />
|
||||
<ClInclude Include="..\Utilities\cfmt.h" />
|
||||
<ClInclude Include="..\Utilities\dynamic_library.h" />
|
||||
<ClInclude Include="..\Utilities\event.h" />
|
||||
|
@ -1453,9 +1453,6 @@
|
||||
<ClInclude Include="..\Utilities\geometry.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Utilities\BitSet.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\PSP2\ARMv7Callback.h">
|
||||
<Filter>Emu\PSP2</Filter>
|
||||
</ClInclude>
|
||||
@ -1708,5 +1705,8 @@
|
||||
<ClInclude Include="..\Utilities\cfmt.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Utilities\bit_set.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user