From 46735d6b3da32602c315ddaa46ff9b14667be84a Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sun, 7 Aug 2016 22:01:27 +0300 Subject: [PATCH] New bitsets (experimental) --- Utilities/BitSet.h | 269 ----------- Utilities/File.cpp | 30 +- Utilities/File.h | 26 +- Utilities/StrFmt.h | 26 + Utilities/bit_set.h | 636 +++++++++++++++++++++++++ rpcs3/Emu/CPU/CPUThread.cpp | 39 +- rpcs3/Emu/CPU/CPUThread.h | 10 +- rpcs3/Emu/Cell/PPUAnalyser.cpp | 42 +- rpcs3/Emu/Cell/PPUAnalyser.h | 6 +- rpcs3/Emu/Cell/PPUThread.cpp | 13 +- rpcs3/Emu/Cell/PPUTranslator.cpp | 2 +- rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp | 8 +- rpcs3/Emu/Cell/SPUThread.cpp | 22 +- rpcs3/Emu/Cell/lv2/sys_fs.cpp | 6 +- rpcs3/Emu/Cell/lv2/sys_interrupt.cpp | 4 +- rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp | 2 +- rpcs3/Emu/PSP2/ARMv7Thread.cpp | 4 +- rpcs3/Gui/InterpreterDisAsm.cpp | 10 +- rpcs3/emucore.vcxproj | 2 +- rpcs3/emucore.vcxproj.filters | 6 +- 20 files changed, 802 insertions(+), 361 deletions(-) delete mode 100644 Utilities/BitSet.h create mode 100644 Utilities/bit_set.h diff --git a/Utilities/BitSet.h b/Utilities/BitSet.h deleted file mode 100644 index e2531b4225..0000000000 --- a/Utilities/BitSet.h +++ /dev/null @@ -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). -// Internal representation is single value of type T. -template -struct bitset_t -{ - using type = simple_t; - using under = std::underlying_type_t; - enum class raw_type : under {}; - - static constexpr auto bitsize = BitSize; - - bitset_t() = default; - - constexpr bitset_t(type _enum_const) - : m_value(static_cast(shift(_enum_const))) - { - } - - constexpr bitset_t(raw_type raw_value) - : m_value(static_cast(static_cast(raw_value))) - { - } - - // Get underlying value - constexpr under _value() const - { - return static_cast(m_value); - } - - explicit constexpr operator bool() const - { - return _value() ? true : false; - } - - bitset_t& operator +=(bitset_t rhs) - { - return *this = static_cast(_value() | rhs._value()); - } - - bitset_t& operator -=(bitset_t rhs) - { - return *this = static_cast(_value() & ~rhs._value()); - } - - bitset_t& operator &=(bitset_t rhs) - { - return *this = static_cast(_value() & rhs._value()); - } - - bitset_t& operator ^=(bitset_t rhs) - { - return *this = static_cast(_value() ^ rhs._value()); - } - - friend constexpr bitset_t operator +(bitset_t lhs, bitset_t rhs) - { - return static_cast(lhs._value() | rhs._value()); - } - - friend constexpr bitset_t operator -(bitset_t lhs, bitset_t rhs) - { - return static_cast(lhs._value() & ~rhs._value()); - } - - friend constexpr bitset_t operator &(bitset_t lhs, bitset_t rhs) - { - return static_cast(lhs._value() & rhs._value()); - } - - friend constexpr bitset_t operator ^(bitset_t lhs, bitset_t rhs) - { - return static_cast(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(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(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(v ^ s); - return (v & s) != 0; - } - -private: - static constexpr under shift(const T& value) - { - return static_cast(value) < BitSize ? static_cast(1) << static_cast(value) : throw value; - } - - T m_value; -}; - -template -constexpr RT make_bitset() -{ - return RT{}; -} - -// Fold enum constants into bitset_t<> (must be implemented with constexpr initializer_list constructor instead) -template::value, bitset_t, T>> -constexpr RT make_bitset(Arg&& _enum_const, Args&&... args) -{ - return RT{ std::forward(_enum_const) } + make_bitset(std::forward(args)...); -} - -template -struct atomic_add, CT, std::enable_if_t::value>> -{ - using under = typename bitset_t::under; - using raw_type = typename bitset_t::raw_type; - - static inline bitset_t op1(bitset_t& left, bitset_t right) - { - return static_cast(atomic_storage::fetch_or(reinterpret_cast(left), right._value())); - } - - static constexpr auto fetch_op = &op1; - - static inline bitset_t op2(bitset_t& left, bitset_t right) - { - return static_cast(atomic_storage::or_fetch(reinterpret_cast(left), right._value())); - } - - static constexpr auto op_fetch = &op2; - static constexpr auto atomic_op = &op2; -}; - -template -struct atomic_sub, CT, std::enable_if_t::value>> -{ - using under = typename bitset_t::under; - using raw_type = typename bitset_t::raw_type; - - static inline bitset_t op1(bitset_t& left, bitset_t right) - { - return static_cast(atomic_storage::fetch_and(reinterpret_cast(left), ~right._value())); - } - - static constexpr auto fetch_op = &op1; - - static inline bitset_t op2(bitset_t& left, bitset_t right) - { - return static_cast(atomic_storage::and_fetch(reinterpret_cast(left), ~right._value())); - } - - static constexpr auto op_fetch = &op2; - static constexpr auto atomic_op = &op2; -}; - -template -struct atomic_and, CT, std::enable_if_t::value>> -{ - using under = typename bitset_t::under; - using raw_type = typename bitset_t::raw_type; - - static inline bitset_t op1(bitset_t& left, bitset_t right) - { - return static_cast(atomic_storage::fetch_and(reinterpret_cast(left), right._value())); - } - - static constexpr auto fetch_op = &op1; - - static inline bitset_t op2(bitset_t& left, bitset_t right) - { - return static_cast(atomic_storage::and_fetch(reinterpret_cast(left), right._value())); - } - - static constexpr auto op_fetch = &op2; - static constexpr auto atomic_op = &op2; -}; - -template -struct atomic_xor, CT, std::enable_if_t::value>> -{ - using under = typename bitset_t::under; - using raw_type = typename bitset_t::raw_type; - - static inline bitset_t op1(bitset_t& left, bitset_t right) - { - return static_cast(atomic_storage::fetch_xor(reinterpret_cast(left), right._value())); - } - - static constexpr auto fetch_op = &op1; - - static inline bitset_t op2(bitset_t& left, bitset_t right) - { - return static_cast(atomic_storage::xor_fetch(reinterpret_cast(left), right._value())); - } - - static constexpr auto op_fetch = &op2; - static constexpr auto atomic_op = &op2; -}; - -template -struct atomic_test_and_set, T, std::enable_if_t::value>> -{ - using under = typename bitset_t::under; - - static inline bool _op(bitset_t& left, const T& value) - { - return atomic_storage::bts(reinterpret_cast(left), static_cast(value)); - } - - static constexpr auto atomic_op = &_op; -}; - -template -struct atomic_test_and_reset, T, std::enable_if_t::value>> -{ - using under = typename bitset_t::under; - - static inline bool _op(bitset_t& left, const T& value) - { - return atomic_storage::btr(reinterpret_cast(left), static_cast(value)); - } - - static constexpr auto atomic_op = &_op; -}; - -template -struct atomic_test_and_complement, T, std::enable_if_t::value>> -{ - using under = typename bitset_t::under; - - static inline bool _op(bitset_t& left, const T& value) - { - return atomic_storage::btc(reinterpret_cast(left), static_cast(value)); - } - - static constexpr auto atomic_op = &_op; -}; - -template -struct fmt_unveil, void> -{ - using type = typename bitset_t::raw_type; - - static inline auto get(const bitset_t& value) - { - return fmt_unveil::get(static_cast(value._value())); - } -}; diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 0ecac5b390..a1010be805 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -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 mode) +bool fs::file::open(const std::string& path, bs_t mode) { if (auto device = get_virtual_device(path)) { @@ -645,25 +645,25 @@ bool fs::file::open(const std::string& path, bitset_t 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 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); diff --git a/Utilities/File.h b/Utilities/File.h index 25ebe364b2..ddffd4667a 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -6,12 +6,12 @@ #include #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 read = open_mode::read; // Enable reading - constexpr bitset_t write = open_mode::write; // Enable writing - constexpr bitset_t append = open_mode::append; // Always append to the end of the file - constexpr bitset_t create = open_mode::create; // Create file if it doesn't exist - constexpr bitset_t trunc = open_mode::trunc; // Clear opened file if it's not empty - constexpr bitset_t 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 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 open(const std::string& path, bitset_t mode) = 0; + virtual std::unique_ptr open(const std::string& path, bs_t mode) = 0; virtual std::unique_ptr 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 mode = ::fs::read) + explicit file(const std::string& path, bs_t mode = ::fs::read) { open(path, mode); } // Open file with specified mode - bool open(const std::string& path, bitset_t mode = ::fs::read); + bool open(const std::string& path, bs_t mode = ::fs::read); // Open memory for read explicit file(const void* ptr, std::size_t size); diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index ab430838dd..88825cb99b 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -146,6 +146,32 @@ struct fmt_class_string fmt_class_string>::format(out, static_cast(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::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; }; diff --git a/Utilities/bit_set.h b/Utilities/bit_set.h new file mode 100644 index 0000000000..9d81c94cf1 --- /dev/null +++ b/Utilities/bit_set.h @@ -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`. +These are very different from previously described bitwise operators. + +Examples: +`+flagzz::flag1` - unary `+` operator convert flagzz value to bs_t +`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 +struct bs_base +{ + // Underlying type + using under = std::underlying_type_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(T::__bitset_enum_max); + + static_assert(std::is_enum::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(1) << static_cast(value); + } + + friend type& operator +=(type& lhs, type rhs) + { + reinterpret_cast(lhs) |= static_cast(rhs); + return lhs; + } + + friend type& operator -=(type& lhs, type rhs) + { + reinterpret_cast(lhs) &= ~static_cast(rhs); + return lhs; + } + + friend type& operator &=(type& lhs, type rhs) + { + reinterpret_cast(lhs) &= static_cast(rhs); + return lhs; + } + + friend type& operator ^=(type& lhs, type rhs) + { + reinterpret_cast(lhs) ^= static_cast(rhs); + return lhs; + } + + friend type& operator +=(type& lhs, T rhs) + { + reinterpret_cast(lhs) |= shift(rhs); + return lhs; + } + + friend type& operator -=(type& lhs, T rhs) + { + reinterpret_cast(lhs) &= ~shift(rhs); + return lhs; + } + + friend type& operator &=(type& lhs, T rhs) + { + reinterpret_cast(lhs) &= shift(rhs); + return lhs; + } + + friend type& operator ^=(type& lhs, T rhs) + { + reinterpret_cast(lhs) ^= shift(rhs); + return lhs; + } + + friend constexpr type operator +(type lhs, type rhs) + { + return static_cast(static_cast(lhs) | static_cast(rhs)); + } + + friend constexpr type operator -(type lhs, type rhs) + { + return static_cast(static_cast(lhs) & ~static_cast(rhs)); + } + + friend constexpr type operator &(type lhs, type rhs) + { + return static_cast(static_cast(lhs) & static_cast(rhs)); + } + + friend constexpr type operator ^(type lhs, type rhs) + { + return static_cast(static_cast(lhs) ^ static_cast(rhs)); + } + + friend constexpr type operator &(type lhs, T rhs) + { + return static_cast(static_cast(lhs) & shift(rhs)); + } + + friend constexpr type operator ^(type lhs, T rhs) + { + return static_cast(static_cast(lhs) ^ shift(rhs)); + } + + friend constexpr type operator &(T lhs, type rhs) + { + return static_cast(shift(lhs) & static_cast(rhs)); + } + + friend constexpr type operator ^(T lhs, type rhs) + { + return static_cast(shift(lhs) ^ static_cast(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(value) != 0; + } + + friend constexpr bool test(type lhs, type rhs) + { + return (static_cast(lhs) & static_cast(rhs)) != 0; + } + + friend constexpr bool test(type lhs, T rhs) + { + return (static_cast(lhs) & shift(rhs)) != 0; + } + + friend constexpr bool test(T lhs, type rhs) + { + return (shift(lhs) & static_cast(rhs)) != 0; + } + + friend constexpr bool test_and_set(type& lhs, type rhs) + { + return test_and_set(reinterpret_cast(lhs), static_cast(rhs)); + } + + friend constexpr bool test_and_set(type& lhs, T rhs) + { + return test_and_set(reinterpret_cast(lhs), shift(rhs)); + } + + friend constexpr bool test_and_reset(type& lhs, type rhs) + { + return test_and_reset(reinterpret_cast(lhs), static_cast(rhs)); + } + + friend constexpr bool test_and_reset(type& lhs, T rhs) + { + return test_and_reset(reinterpret_cast(lhs), shift(rhs)); + } + + friend constexpr bool test_and_complement(type& lhs, type rhs) + { + return test_and_complement(reinterpret_cast(lhs), static_cast(rhs)); + } + + friend constexpr bool test_and_complement(type& lhs, T rhs) + { + return test_and_complement(reinterpret_cast(lhs), shift(rhs)); + } +}; + +// Bitset type for enum class with available bits [0, T::__bitset_enum_max) +template +using bs_t = typename bs_base::type; + +// Unary '+' operator: promote plain enum value to bitset value +template +constexpr bs_t operator +(T value) +{ + return static_cast>(bs_base::shift(value)); +} + +// Binary '+' operator: bitset union +template +constexpr bs_t operator +(T lhs, T rhs) +{ + return static_cast>(bs_base::shift(lhs) | bs_base::shift(rhs)); +} + +// Binary '+' operator: bitset union +template +constexpr bs_t operator +(typename bs_base::type lhs, T rhs) +{ + return static_cast>(static_cast::under>(lhs) | bs_base::shift(rhs)); +} + +// Binary '+' operator: bitset union +template +constexpr bs_t operator +(T lhs, typename bs_base::type rhs) +{ + return static_cast>(bs_base::shift(lhs) | static_cast::under>(rhs)); +} + +// Binary '-' operator: bitset difference +template +constexpr bs_t operator -(T lhs, T rhs) +{ + return static_cast>(bs_base::shift(lhs) & ~bs_base::shift(rhs)); +} + +// Binary '-' operator: bitset difference +template +constexpr bs_t operator -(typename bs_base::type lhs, T rhs) +{ + return static_cast>(static_cast::under>(lhs) & ~bs_base::shift(rhs)); +} + +// Binary '-' operator: bitset difference +template +constexpr bs_t operator -(T lhs, typename bs_base::type rhs) +{ + return static_cast>(bs_base::shift(lhs) & ~static_cast::under>(rhs)); +} + +template +struct atomic_add>::value>>> +{ + using under = typename bs_base::under; + + static inline bs_t op1(bs_t& left, T right) + { + return static_cast>(atomic_storage::fetch_or(reinterpret_cast(left), bs_base::shift(right))); + } + + static constexpr auto fetch_op = &op1; + + static inline bs_t op2(bs_t& left, T right) + { + return static_cast>(atomic_storage::or_fetch(reinterpret_cast(left), bs_base::shift(right))); + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_sub>::value>>> +{ + using under = typename bs_base::under; + + static inline bs_t op1(bs_t& left, T right) + { + return static_cast>(atomic_storage::fetch_and(reinterpret_cast(left), ~bs_base::shift(right))); + } + + static constexpr auto fetch_op = &op1; + + static inline bs_t op2(bs_t& left, T right) + { + return static_cast>(atomic_storage::and_fetch(reinterpret_cast(left), ~bs_base::shift(right))); + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_and>::value>>> +{ + using under = typename bs_base::under; + + static inline bs_t op1(bs_t& left, T right) + { + return static_cast>(atomic_storage::fetch_and(reinterpret_cast(left), bs_base::shift(right))); + } + + static constexpr auto fetch_op = &op1; + + static inline bs_t op2(bs_t& left, T right) + { + return static_cast>(atomic_storage::and_fetch(reinterpret_cast(left), bs_base::shift(right))); + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_xor>::value>>> +{ + using under = typename bs_base::under; + + static inline bs_t op1(bs_t& left, T right) + { + return static_cast>(atomic_storage::fetch_xor(reinterpret_cast(left), bs_base::shift(right))); + } + + static constexpr auto fetch_op = &op1; + + static inline bs_t op2(bs_t& left, T right) + { + return static_cast>(atomic_storage::xor_fetch(reinterpret_cast(left), bs_base::shift(right))); + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_add> +{ + using under = std::underlying_type_t; + + static inline T op1(T& left, T right) + { + return static_cast(atomic_storage::fetch_or(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto fetch_op = &op1; + + static inline T op2(T& left, T right) + { + return static_cast(atomic_storage::or_fetch(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_sub> +{ + using under = std::underlying_type_t; + + static inline T op1(T& left, T right) + { + return static_cast(atomic_storage::fetch_and(reinterpret_cast(left), ~static_cast(right))); + } + + static constexpr auto fetch_op = &op1; + + static inline T op2(T& left, T right) + { + return static_cast(atomic_storage::and_fetch(reinterpret_cast(left), ~static_cast(right))); + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_and> +{ + using under = std::underlying_type_t; + + static inline T op1(T& left, T right) + { + return static_cast(atomic_storage::fetch_and(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto fetch_op = &op1; + + static inline T op2(T& left, T right) + { + return static_cast(atomic_storage::and_fetch(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_xor> +{ + using under = std::underlying_type_t; + + static inline T op1(T& left, T right) + { + return static_cast(atomic_storage::fetch_xor(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto fetch_op = &op1; + + static inline T op2(T& left, T right) + { + return static_cast(atomic_storage::xor_fetch(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_test_and_set>::value>>> +{ + using under = typename bs_base::under; + + static inline bool _op(bs_t& left, T value) + { + return atomic_storage::bts(reinterpret_cast(left), static_cast(static_cast(value))); + } + + static constexpr auto atomic_op = &_op; +}; + +template +struct atomic_test_and_reset>::value>>> +{ + using under = typename bs_base::under; + + static inline bool _op(bs_t& left, T value) + { + return atomic_storage::btr(reinterpret_cast(left), static_cast(static_cast(value))); + } + + static constexpr auto atomic_op = &_op; +}; + +template +struct atomic_test_and_complement>::value>>> +{ + using under = typename bs_base::under; + + static inline bool _op(bs_t& left, T value) + { + return atomic_storage::btc(reinterpret_cast(left), static_cast(static_cast(value))); + } + + static constexpr auto atomic_op = &_op; +}; + +// Binary '|' operator: bitwise OR +template +constexpr T operator |(T lhs, T rhs) +{ + return static_cast(std::underlying_type_t(lhs) | std::underlying_type_t(rhs)); +} + +// Binary '&' operator: bitwise AND +template +constexpr T operator &(T lhs, T rhs) +{ + return static_cast(std::underlying_type_t(lhs) & std::underlying_type_t(rhs)); +} + +// Binary '^' operator: bitwise XOR +template +constexpr T operator ^(T lhs, T rhs) +{ + return static_cast(std::underlying_type_t(lhs) ^ std::underlying_type_t(rhs)); +} + +// Unary '~' operator: bitwise NEG +template +constexpr T operator ~(T value) +{ + return static_cast(~std::underlying_type_t(value)); +} + +// Bitwise OR assignment +template +inline T& operator |=(T& lhs, T rhs) +{ + reinterpret_cast&>(lhs) |= std::underlying_type_t(rhs); + return lhs; +} + +// Bitwise AND assignment +template +inline T& operator &=(T& lhs, T rhs) +{ + reinterpret_cast&>(lhs) &= std::underlying_type_t(rhs); + return lhs; +} + +// Bitwise XOR assignment +template +inline T& operator ^=(T& lhs, T rhs) +{ + reinterpret_cast&>(lhs) ^= std::underlying_type_t(rhs); + return lhs; +} + +template +constexpr bool test(T value) +{ + return std::underlying_type_t(value) != 0; +} + +template +constexpr bool test(T lhs, T rhs) +{ + return (std::underlying_type_t(lhs) & std::underlying_type_t(rhs)) != 0; +} + +template +inline bool test_and_set(T& lhs, T rhs) +{ + return test_and_set(reinterpret_cast&>(lhs), std::underlying_type_t(rhs)); +} + +template +inline bool test_and_reset(T& lhs, T rhs) +{ + return test_and_reset(reinterpret_cast&>(lhs), std::underlying_type_t(rhs)); +} + +template +inline bool test_and_complement(T& lhs, T rhs) +{ + return test_and_complement(reinterpret_cast&>(lhs), std::underlying_type_t(rhs)); +} + +template +struct atomic_or::value>>> +{ + using under = std::underlying_type_t; + + static inline T op1(T& left, T right) + { + return static_cast(atomic_storage::fetch_or(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto fetch_op = &op1; + + static inline T op2(T& left, T right) + { + return static_cast(atomic_storage::or_fetch(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_and::value>>> +{ + using under = std::underlying_type_t; + + static inline T op1(T& left, T right) + { + return static_cast(atomic_storage::fetch_and(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto fetch_op = &op1; + + static inline T op2(T& left, T right) + { + return static_cast(atomic_storage::and_fetch(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_xor::value>>> +{ + using under = std::underlying_type_t; + + static inline T op1(T& left, T right) + { + return static_cast(atomic_storage::fetch_xor(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto fetch_op = &op1; + + static inline T op2(T& left, T right) + { + return static_cast(atomic_storage::xor_fetch(reinterpret_cast(left), static_cast(right))); + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 5b826a04e5..bb853a21d8 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -21,9 +21,32 @@ void fmt_class_string::format(std::string& out, u64 arg) } template<> -void fmt_class_string::raw_type>::format(std::string& out, u64 arg) +void fmt_class_string::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>::format(std::string& out, u64 arg) +{ + format_bitset(out, arg, "[", "|", "]", &fmt_class_string::format); } thread_local cpu_thread* g_tls_current_cpu_thread = nullptr; @@ -39,12 +62,12 @@ void cpu_thread::on_task() std::unique_lock 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; diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 9280b0d78c..7507f16ea7 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -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_pause = make_bitset(cpu_state::suspend, cpu_state::dbg_global_pause, cpu_state::dbg_pause); +constexpr bs_t 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> state{ cpu_state::stop }; + atomic_t> state{+cpu_state::stop}; // Object associated with sleep state, possibly synchronization primitive (mutex, semaphore, etc.) atomic_t owner{}; diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index 130b3acaa9..ffcbae87cc 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -11,9 +11,30 @@ const ppu_decoder s_ppu_itype; const ppu_decoder s_ppu_iname; template<> -void fmt_class_string::raw_type>::format(std::string& out, u64 arg) +void fmt_class_string::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>::format(std::string& out, u64 arg) +{ + format_bitset(out, arg, "[", ",", "]", &fmt_class_string::format); } void ppu_validate(const std::string& fname, const std::vector& funcs, u32 reloc) @@ -377,7 +398,7 @@ std::vector ppu_analyse(const std::vector>& 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_analyse(const std::vector>& se } // Get function limit - const u32 func_end = std::min(get_limit(func.addr + 1), func.attr & ppu_attr::known_size ? func.addr + func.size : end); + const u32 func_end = std::min(get_limit(func.addr + 1), test(func.attr, ppu_attr::known_size) ? func.addr + func.size : end); // Block analysis workload std::vector>> block_queue; @@ -715,7 +736,7 @@ std::vector ppu_analyse(const std::vector>& 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_analyse(const std::vector>& 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_analyse(const std::vector>& 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_analyse(const std::vector>& 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_analyse(const std::vector>& 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(); diff --git a/rpcs3/Emu/Cell/PPUAnalyser.h b/rpcs3/Emu/Cell/PPUAnalyser.h index 859d61038b..98e71e5a7e 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.h +++ b/rpcs3/Emu/Cell/PPUAnalyser.h @@ -3,7 +3,7 @@ #include #include -#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 attr{}; + bs_t attr{}; u32 stack_frame = 0; u32 gate_target = 0; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 93e80cd4aa..6499dc76ff 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -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); } diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index 3d87f8baa1..856cb4798b 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -128,7 +128,7 @@ Function* PPUTranslator::TranslateToIR(const ppu_function& info, be_t* 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"); diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index e6525200fd..20f560fa66 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -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(cpu_state::stop + cpu_state::ret)); c->jmp(*end); c->unuse(*addr); return; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 95b10ca827..f7dcf57f98 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -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; } diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index acc9622121..a5e2e4903a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -79,7 +79,7 @@ ppu_error_code sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 return CELL_EISDIR; } - bitset_t open_mode{}; + bs_t open_mode{}; switch (flags & CELL_FS_O_ACCMODE) { @@ -125,7 +125,7 @@ ppu_error_code sys_fs_open(vm::cptr path, s32 flags, vm::ptr 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 path, s32 flags, vm::ptr 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 } diff --git a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp index 57f04ed0c3..01ed65b9b6 100644 --- a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp @@ -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 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; } diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index 1b896b9a29..a654e2195f 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -68,7 +68,7 @@ s32 sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr vptr) thread->is_joining = true; // join thread - while (!(thread->state & cpu_state::exit)) + while (!test(thread->state & cpu_state::exit)) { CHECK_EMU_STATUS; diff --git a/rpcs3/Emu/PSP2/ARMv7Thread.cpp b/rpcs3/Emu/PSP2/ARMv7Thread.cpp index f83320bdbc..fc2e147562 100644 --- a/rpcs3/Emu/PSP2/ARMv7Thread.cpp +++ b/rpcs3/Emu/PSP2/ARMv7Thread.cpp @@ -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); } diff --git a/rpcs3/Gui/InterpreterDisAsm.cpp b/rpcs3/Gui/InterpreterDisAsm.cpp index dcb4b0e3a8..d0d305c236 100644 --- a/rpcs3/Gui/InterpreterDisAsm.cpp +++ b/rpcs3/Gui/InterpreterDisAsm.cpp @@ -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& state) -> bool + if (test(cpu_state::dbg_pause, cpu->state.fetch_op([](bs_t& state) { state += cpu_state::dbg_step; - return state.test_and_reset(cpu_state::dbg_pause); - })) + state -= cpu_state::dbg_pause; + }))) { (*cpu)->lock_notify(); } diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 3221b190d6..e41b4a23f3 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -386,7 +386,7 @@ - + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 30ae6212e6..d8c20193c0 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1453,9 +1453,6 @@ Utilities - - Utilities - Emu\PSP2 @@ -1708,5 +1705,8 @@ Utilities + + Utilities + \ No newline at end of file