New bitsets (experimental)

This commit is contained in:
Nekotekina 2016-08-07 22:01:27 +03:00
parent 71441819e5
commit 46735d6b3d
20 changed files with 802 additions and 361 deletions

View File

@ -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()));
}
};

View File

@ -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);

View File

@ -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);

View File

@ -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
View 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;
};

View File

@ -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;

View File

@ -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{};

View File

@ -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();

View File

@ -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;

View File

@ -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);
}

View File

@ -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");

View File

@ -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;

View File

@ -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;
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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" />

View File

@ -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>