cpu_type removed, system_type added

cpu_state -> cpu_flag
vm::stack_allocator template improved
ppu_cmd type changed to enum, cmd64 type added
This commit is contained in:
Nekotekina 2016-08-09 17:14:41 +03:00
parent 009ac37a7d
commit bdeccd889f
39 changed files with 449 additions and 492 deletions

View File

@ -9,10 +9,8 @@ static struct defer_sleep_tag {} constexpr defer_sleep{};
template<typename T> using sleep_queue = std::deque<T*>;
// Automatic object handling a thread pointer (T*) in the sleep queue
// Sleep is called in the constructor (if not null)
// Awake is called in the destructor (if not null)
// Sleep queue is actually std::deque with pointers, be careful about the lifetime
template<typename T, void(T::*Sleep)() = nullptr, void(T::*Awake)() = nullptr>
template<typename T>
class sleep_entry final
{
sleep_queue<T>& m_queue;
@ -24,7 +22,6 @@ public:
: m_queue(queue)
, m_thread(entry)
{
if (Sleep) (m_thread.*Sleep)();
}
// Constructor; calls enter()
@ -38,7 +35,6 @@ public:
~sleep_entry()
{
leave();
if (Awake) (m_thread.*Awake)();
}
// Add thread to the sleep queue

View File

@ -543,6 +543,62 @@ using any16 = any_pod<simple_t, sizeof(u16)>;
using any32 = any_pod<simple_t, sizeof(u32)>;
using any64 = any_pod<simple_t, sizeof(u64)>;
struct cmd64 : any64
{
struct pair_t
{
any32 arg1;
any32 arg2;
};
cmd64() = default;
template<typename T>
cmd64(const T& value)
: any64(value)
{
}
template<typename T1, typename T2>
cmd64(const T1& arg1, const T2& arg2)
: any64(pair_t{arg1, arg2})
{
}
explicit operator bool() const
{
return as<u64>() != 0;
}
// TODO: compatibility with std::pair/std::tuple?
template<typename T>
decltype(auto) arg1()
{
return as<pair_t>().arg1.as<T>();
}
template<typename T>
decltype(auto) arg1() const
{
return as<const pair_t>().arg1.as<const T>();
}
template<typename T>
decltype(auto) arg2()
{
return as<pair_t>().arg2.as<T>();
}
template<typename T>
decltype(auto) arg2() const
{
return as<const pair_t>().arg2.as<const T>();
}
};
static_assert(sizeof(cmd64) == 8 && std::is_pod<cmd64>::value, "Incorrect cmd64 type");
// Allows to define integer convertible to multiple types
template<typename T, T Value, typename T1 = void, typename... Ts>
struct multicast : multicast<T, Value, Ts...>

View File

@ -5,38 +5,22 @@
#include <mutex>
template<>
void fmt_class_string<cpu_type>::format(std::string& out, u64 arg)
void fmt_class_string<cpu_flag>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](auto arg)
{
switch (arg)
{
STR_CASE(cpu_type::ppu);
STR_CASE(cpu_type::spu);
STR_CASE(cpu_type::arm);
}
return unknown;
});
}
template<>
void fmt_class_string<cpu_state>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](cpu_state f)
format_enum(out, arg, [](cpu_flag 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;
STR_CASE(cpu_flag::stop);
STR_CASE(cpu_flag::exit);
STR_CASE(cpu_flag::suspend);
STR_CASE(cpu_flag::ret);
STR_CASE(cpu_flag::signal);
STR_CASE(cpu_flag::dbg_global_pause);
STR_CASE(cpu_flag::dbg_global_stop);
STR_CASE(cpu_flag::dbg_pause);
STR_CASE(cpu_flag::dbg_step);
case cpu_flag::__bitset_enum_max: break;
}
return unknown;
@ -44,16 +28,16 @@ void fmt_class_string<cpu_state>::format(std::string& out, u64 arg)
}
template<>
void fmt_class_string<bs_t<cpu_state>>::format(std::string& out, u64 arg)
void fmt_class_string<bs_t<cpu_flag>>::format(std::string& out, u64 arg)
{
format_bitset(out, arg, "[", "|", "]", &fmt_class_string<cpu_state>::format);
format_bitset(out, arg, "[", "|", "]", &fmt_class_string<cpu_flag>::format);
}
thread_local cpu_thread* g_tls_current_cpu_thread = nullptr;
void cpu_thread::on_task()
{
state -= cpu_state::exit;
state -= cpu_flag::exit;
g_tls_current_cpu_thread = this;
@ -62,12 +46,12 @@ void cpu_thread::on_task()
std::unique_lock<named_thread> lock(*this);
// Check thread status
while (!test(state & cpu_state::exit))
while (!test(state & cpu_flag::exit))
{
CHECK_EMU_STATUS;
// check stop status
if (!test(state & cpu_state::stop))
if (!test(state & cpu_flag::stop))
{
if (lock) lock.unlock();
@ -75,7 +59,7 @@ void cpu_thread::on_task()
{
cpu_task();
}
catch (cpu_state _s)
catch (cpu_flag _s)
{
state += _s;
}
@ -85,7 +69,7 @@ void cpu_thread::on_task()
throw;
}
state -= cpu_state::ret;
state -= cpu_flag::ret;
continue;
}
@ -101,7 +85,7 @@ void cpu_thread::on_task()
void cpu_thread::on_stop()
{
state += cpu_state::exit;
state += cpu_flag::exit;
lock_notify();
}
@ -109,8 +93,7 @@ cpu_thread::~cpu_thread()
{
}
cpu_thread::cpu_thread(cpu_type type)
: type(type)
cpu_thread::cpu_thread()
{
}
@ -122,7 +105,7 @@ bool cpu_thread::check_state()
{
CHECK_EMU_STATUS; // check at least once
if (test(state & cpu_state::exit))
if (test(state & cpu_flag::exit))
{
return true;
}
@ -143,15 +126,15 @@ bool cpu_thread::check_state()
const auto state_ = state.load();
if (test(state_, cpu_state::ret + cpu_state::stop))
if (test(state_, cpu_flag::ret + cpu_flag::stop))
{
return true;
}
if (test(state_, cpu_state::dbg_step))
if (test(state_, cpu_flag::dbg_step))
{
state += cpu_state::dbg_pause;
state -= cpu_state::dbg_step;
state += cpu_flag::dbg_pause;
state -= cpu_flag::dbg_step;
}
return false;
@ -159,6 +142,6 @@ bool cpu_thread::check_state()
void cpu_thread::run()
{
state -= cpu_state::stop;
state -= cpu_flag::stop;
lock_notify();
}

View File

@ -3,16 +3,8 @@
#include "../Utilities/Thread.h"
#include "../Utilities/bit_set.h"
// CPU Thread Type (TODO: probably remove, use id and idm to classify threads)
enum class cpu_type : u8
{
ppu, // PPU Thread
spu, // SPU Thread
arm, // ARMv7 Thread
};
// CPU Thread State flags (TODO: use u32 once cpu_type is removed)
enum class cpu_state : u16
// cpu_thread state flags
enum class cpu_flag : u32
{
stop, // Thread not running (HLE, initial state)
exit, // Irreversible exit
@ -28,8 +20,8 @@ enum class cpu_state : u16
__bitset_enum_max
};
// CPU Thread State flags: pause state union
constexpr bs_t<cpu_state> cpu_state_pause = cpu_state::suspend + cpu_state::dbg_global_pause + cpu_state::dbg_pause;
// cpu_flag set for pause state
constexpr bs_t<cpu_flag> cpu_state_pause = cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause;
class cpu_thread : public named_thread
{
@ -40,12 +32,11 @@ public:
virtual ~cpu_thread() override;
const id_value<> id{};
const cpu_type type;
cpu_thread(cpu_type type);
cpu_thread();
// Public thread state
atomic_t<bs_t<cpu_state>> state{+cpu_state::stop};
atomic_t<bs_t<cpu_flag>> state{+cpu_flag::stop};
// Object associated with sleep state, possibly synchronization primitive (mutex, semaphore, etc.)
atomic_t<void*> owner{};

View File

@ -699,11 +699,11 @@ struct fs_aio_thread : ppu_thread
virtual void cpu_task() override
{
while (ppu_cmd cmd = cmd_wait())
while (cmd64 cmd = cmd_wait())
{
const u32 type = cmd.arg1<u32>();
const s32 xid = cmd.arg2<s32>();
const ppu_cmd cmd2 = cmd_queue[cmd_queue.peek() + 1];
const cmd64 cmd2 = cmd_get(1);
const auto aio = cmd2.arg1<vm::ptr<CellFsAio>>();
const auto func = cmd2.arg2<fs_aio_cb_t>();
cmd_pop(1);

View File

@ -1819,7 +1819,7 @@ void spursTasksetDispatch(SPUThread& spu)
{
// TODO: Figure this out
spu.status |= SPU_STATUS_STOPPED_BY_STOP;
throw cpu_state::stop;
throw cpu_flag::stop;
}
spursTasksetStartTask(spu, taskInfo->args);
@ -1873,7 +1873,7 @@ void spursTasksetDispatch(SPUThread& spu)
{
// TODO: Figure this out
spu.status |= SPU_STATUS_STOPPED_BY_STOP;
throw cpu_state::stop;
throw cpu_flag::stop;
}
spu.gpr[3].clear();

View File

@ -25,7 +25,7 @@ vm::gvar<s32> _cell_vdec_prx_ver; // ???
enum class vdec_cmd : u32
{
none = 0,
null,
start_seq,
end_seq,
@ -150,7 +150,7 @@ struct vdec_thread : ppu_thread
virtual void cpu_task() override
{
while (ppu_cmd cmd = cmd_wait())
while (cmd64 cmd = cmd_wait())
{
switch (vdec_cmd vcmd = cmd.arg1<vdec_cmd>())
{
@ -182,14 +182,13 @@ struct vdec_thread : ppu_thread
if (vcmd == vdec_cmd::decode)
{
const u32 pos = cmd_queue.peek();
au_type = cmd.arg2<u32>(); // TODO
au_addr = cmd_queue[pos + 1].load().arg1<u32>();
au_size = cmd_queue[pos + 1].load().arg2<u32>();
au_pts = cmd_queue[pos + 2].load().as<u64>();
au_dts = cmd_queue[pos + 3].load().as<u64>();
au_usrd = cmd_queue[pos + 4].load().as<u64>(); // TODO
au_spec = cmd_queue[pos + 5].load().as<u64>(); // TODO
au_addr = cmd_get(1).arg1<u32>();
au_size = cmd_get(1).arg2<u32>();
au_pts = cmd_get(2).as<u64>();
au_dts = cmd_get(3).as<u64>();
au_usrd = cmd_get(4).as<u64>(); // TODO
au_spec = cmd_get(5).as<u64>(); // TODO
cmd_pop(5);
packet.data = vm::_ptr<u8>(au_addr);
@ -349,7 +348,7 @@ struct vdec_thread : ppu_thread
case vdec_cmd::close:
{
cmd_pop();
state += cpu_state::exit;
state += cpu_flag::exit;
return;
}

View File

@ -2359,7 +2359,7 @@ s32 ppu_error_code::report(s32 error, const char* text)
{
if (auto thread = get_current_cpu_thread())
{
if (thread->type == cpu_type::ppu)
if (thread->id >= ppu_thread::id_min)
{
if (auto func = static_cast<ppu_thread*>(thread)->last_function)
{
@ -2383,7 +2383,7 @@ std::vector<ppu_function_t>& ppu_function_manager::access()
static std::vector<ppu_function_t> list
{
nullptr,
[](ppu_thread& ppu) { ppu.state += cpu_state::ret; },
[](ppu_thread& ppu) { ppu.state += cpu_flag::ret; },
};
return list;

View File

@ -144,7 +144,7 @@ extern void ppu_execute_function(ppu_thread& ppu, u32 index)
if (index < g_ppu_function_cache.size())
{
// If autopause occures, check_status() will hold the thread until unpaused.
if (debug::autopause::pause_function(g_ppu_fnid_cache[index]) && ppu.check_state()) throw cpu_state::ret;
if (debug::autopause::pause_function(g_ppu_fnid_cache[index]) && ppu.check_state()) throw cpu_flag::ret;
if (const auto func = g_ppu_function_cache[index])
{

View File

@ -118,12 +118,11 @@ void ppu_thread::cpu_task()
//SetHostRoundingMode(FPSCR_RN_NEAR);
// Execute cmd_queue
while (ppu_cmd cmd = cmd_wait())
while (cmd64 cmd = cmd_wait())
{
const u32 pos = cmd_queue.peek() + 1; // Additional arguments start from [pos]
const u32 arg = cmd.arg2<u32>(); // 32-bit arg extracted
switch (u32 type = cmd.arg1<u32>())
switch (auto type = cmd.arg1<ppu_cmd>())
{
case ppu_cmd::opcode:
{
@ -137,7 +136,7 @@ void ppu_thread::cpu_task()
fmt::throw_exception("Invalid ppu_cmd::set_gpr arg (0x%x)" HERE, arg);
}
gpr[arg % 32] = cmd_queue[pos].load().as<u64>();
gpr[arg % 32] = cmd_get(1).as<u64>();
cmd_pop(1);
break;
}
@ -150,7 +149,7 @@ void ppu_thread::cpu_task()
for (u32 i = 0; i < arg; i++)
{
gpr[i + 3] = cmd_queue[pos + i].load().as<u64>();
gpr[i + 3] = cmd_get(1 + i).as<u64>();
}
cmd_pop(arg);
@ -169,7 +168,7 @@ void ppu_thread::cpu_task()
}
default:
{
fmt::throw_exception("Unknown ppu_cmd(0x%x)" HERE, type);
fmt::throw_exception("Unknown ppu_cmd(0x%x)" HERE, (u32)type);
}
}
}
@ -249,7 +248,7 @@ ppu_thread::~ppu_thread()
}
ppu_thread::ppu_thread(const std::string& name, u32 prio, u32 stack)
: cpu_thread(cpu_type::ppu)
: cpu_thread()
, prio(prio)
, stack_size(std::max<u32>(stack, 0x4000))
, stack_addr(vm::alloc(stack_size, vm::stack))
@ -263,7 +262,7 @@ ppu_thread::ppu_thread(const std::string& name, u32 prio, u32 stack)
gpr[1] = ::align(stack_addr + stack_size, 0x200) - 0x200;
}
void ppu_thread::cmd_push(ppu_cmd cmd)
void ppu_thread::cmd_push(cmd64 cmd)
{
// Reserve queue space
const u32 pos = cmd_queue.push_begin();
@ -272,7 +271,7 @@ void ppu_thread::cmd_push(ppu_cmd cmd)
cmd_queue[pos] = cmd;
}
void ppu_thread::cmd_list(std::initializer_list<ppu_cmd> list)
void ppu_thread::cmd_list(std::initializer_list<cmd64> list)
{
// Reserve queue space
const u32 pos = cmd_queue.push_begin(static_cast<u32>(list.size()));
@ -295,14 +294,14 @@ void ppu_thread::cmd_pop(u32 count)
// Clean command buffer for command tail
for (u32 i = 1; i <= count; i++)
{
cmd_queue[pos + i].raw() = ppu_cmd{};
cmd_queue[pos + i].raw() = cmd64{};
}
// Free
cmd_queue.pop_end(count + 1);
}
ppu_cmd ppu_thread::cmd_wait()
cmd64 ppu_thread::cmd_wait()
{
std::unique_lock<named_thread> lock(*this, std::defer_lock);
@ -314,12 +313,12 @@ ppu_cmd ppu_thread::cmd_wait()
if (check_state()) // check_status() requires unlocked mutex
{
return ppu_cmd{};
return cmd64{};
}
}
// Lightweight queue doesn't care about mutex state
if (ppu_cmd result = cmd_queue[cmd_queue.peek()].exchange(ppu_cmd{}))
if (cmd64 result = cmd_queue[cmd_queue.peek()].exchange(cmd64{}))
{
return result;
}
@ -365,15 +364,15 @@ void ppu_thread::fast_call(u32 addr, u32 rtoc)
{
exec_task();
if (gpr[1] != old_stack && !test(state, cpu_state::ret + cpu_state::exit)) // gpr[1] shouldn't change
if (gpr[1] != old_stack && !test(state, cpu_flag::ret + cpu_flag::exit)) // gpr[1] shouldn't change
{
fmt::throw_exception("Stack inconsistency (addr=0x%x, rtoc=0x%x, SP=0x%llx, old=0x%llx)", addr, rtoc, gpr[1], old_stack);
}
}
catch (cpu_state _s)
catch (cpu_flag _s)
{
state += _s;
if (_s != cpu_state::ret) throw;
if (_s != cpu_flag::ret) throw;
}
catch (EmulationStopped)
{
@ -388,7 +387,7 @@ void ppu_thread::fast_call(u32 addr, u32 rtoc)
throw;
}
state -= cpu_state::ret;
state -= cpu_flag::ret;
cia = old_pc;
gpr[1] = old_stack;
@ -398,6 +397,51 @@ void ppu_thread::fast_call(u32 addr, u32 rtoc)
g_tls_log_prefix = old_fmt;
}
u32 ppu_thread::stack_push(u32 size, u32 align_v)
{
if (auto cpu = get_current_cpu_thread()) if (cpu->id >= id_min)
{
ppu_thread& context = static_cast<ppu_thread&>(*cpu);
const u32 old_pos = vm::cast(context.gpr[1], HERE);
context.gpr[1] -= align(size + 4, 8); // room minimal possible size
context.gpr[1] &= ~(align_v - 1); // fix stack alignment
if (context.gpr[1] < context.stack_addr)
{
fmt::throw_exception("Stack overflow (size=0x%x, align=0x%x, SP=0x%llx, stack=*0x%x)" HERE, size, align_v, old_pos, context.stack_addr);
}
else
{
const u32 addr = static_cast<u32>(context.gpr[1]);
vm::ps3::_ref<nse_t<u32>>(addr + size) = old_pos;
std::memset(vm::base(addr), 0, size);
return addr;
}
}
fmt::throw_exception("Invalid thread" HERE);
}
void ppu_thread::stack_pop_verbose(u32 addr, u32 size) noexcept
{
if (auto cpu = get_current_cpu_thread()) if (cpu->id >= id_min)
{
ppu_thread& context = static_cast<ppu_thread&>(*cpu);
if (context.gpr[1] != addr)
{
LOG_ERROR(PPU, "Stack inconsistency (addr=0x%x, SP=0x%llx, size=0x%x)", addr, context.gpr[1], size);
return;
}
context.gpr[1] = vm::ps3::_ref<nse_t<u32>>(context.gpr[1] + size);
return;
}
LOG_ERROR(PPU, "Invalid thread" HERE);
}
const ppu_decoder<ppu_itype> s_ppu_itype;
extern u64 get_timebased_time();

View File

@ -5,75 +5,25 @@
#include "../Memory/vm.h"
#include "Utilities/lockless.h"
// Lightweight PPU command queue element
struct ppu_cmd : any64
enum class ppu_cmd : u32
{
enum : u32
{
none = 0,
null,
opcode, // Execute PPU instruction from arg
set_gpr, // Set gpr[arg] (+1 cmd)
set_args, // Set general-purpose args (+arg cmd)
lle_call, // Load addr and rtoc at *arg or *gpr[arg] and execute
hle_call, // Execute function by index (arg)
};
struct pair_t
{
any32 arg1;
any32 arg2;
};
ppu_cmd() = default;
template<typename T>
ppu_cmd(const T& value)
: any64(value)
{
}
template<typename T1, typename T2>
ppu_cmd(const T1& arg1, const T2& arg2)
: any64(pair_t{arg1, arg2})
{
}
explicit operator bool() const
{
return as<u64>() != 0;
}
template<typename T>
decltype(auto) arg1()
{
return as<pair_t>().arg1.as<T>();
}
template<typename T>
decltype(auto) arg1() const
{
return as<const pair_t>().arg1.as<const T>();
}
template<typename T>
decltype(auto) arg2()
{
return as<pair_t>().arg2.as<T>();
}
template<typename T>
decltype(auto) arg2() const
{
return as<const pair_t>().arg2.as<const T>();
}
opcode, // Execute PPU instruction from arg
set_gpr, // Set gpr[arg] (+1 cmd)
set_args, // Set general-purpose args (+arg cmd)
lle_call, // Load addr and rtoc at *arg or *gpr[arg] and execute
hle_call, // Execute function by index (arg)
};
static_assert(sizeof(ppu_cmd) == 8 && std::is_pod<ppu_cmd>::value, "Incorrect ppu_cmd struct");
class ppu_thread : public cpu_thread
{
public:
using id_base = ppu_thread;
static constexpr u32 id_min = 0x80000000; // TODO (used to determine thread type)
static constexpr u32 id_max = 0x8fffffff;
virtual std::string get_name() const override;
virtual std::string dump() const override;
virtual void cpu_init() override final {}
@ -174,12 +124,13 @@ public:
bool is_joinable = true;
bool is_joining = false;
lf_fifo<atomic_t<ppu_cmd>, 255> cmd_queue; // Command queue for asynchronous operations.
lf_fifo<atomic_t<cmd64>, 255> cmd_queue; // Command queue for asynchronous operations.
void cmd_push(ppu_cmd);
void cmd_list(std::initializer_list<ppu_cmd>);
void cmd_push(cmd64);
void cmd_list(std::initializer_list<cmd64>);
void cmd_pop(u32 = 0);
ppu_cmd cmd_wait(); // Empty command means caller must return, like true from cpu_thread::check_status().
cmd64 cmd_wait(); // Empty command means caller must return, like true from cpu_thread::check_status().
cmd64 cmd_get(u32 index) { return cmd_queue[cmd_queue.peek() + index].load(); }
const char* last_function{}; // Last function name for diagnosis, optimized for speed.
@ -200,6 +151,9 @@ public:
be_t<u64>* get_stack_arg(s32 i, u64 align = alignof(u64));
void exec_task();
void fast_call(u32 addr, u32 rtoc);
static u32 stack_push(u32 size, u32 align_v);
static void stack_pop_verbose(u32 addr, u32 size) noexcept;
};
template<typename T, typename = void>

View File

@ -183,7 +183,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
else if (value == SPU_RUNCNTL_STOP_REQUEST)
{
status &= ~SPU_STATUS_RUNNING;
state += cpu_state::stop;
state += cpu_flag::stop;
}
else
{

View File

@ -14,11 +14,11 @@
#include "asmjit.h"
#define SPU_OFF_128(x) asmjit::host::oword_ptr(*cpu, OFFSET_32(SPUThread, x))
#define SPU_OFF_64(x) asmjit::host::qword_ptr(*cpu, OFFSET_32(SPUThread, x))
#define SPU_OFF_32(x) asmjit::host::dword_ptr(*cpu, OFFSET_32(SPUThread, x))
#define SPU_OFF_16(x) asmjit::host::word_ptr(*cpu, OFFSET_32(SPUThread, x))
#define SPU_OFF_8(x) asmjit::host::byte_ptr(*cpu, OFFSET_32(SPUThread, x))
#define SPU_OFF_128(x) asmjit::host::oword_ptr(*cpu, (std::conditional_t<sizeof(SPUThread::x) == 16, u32, void>)OFFSET_32(SPUThread, x))
#define SPU_OFF_64(x) asmjit::host::qword_ptr(*cpu, (std::conditional_t<sizeof(SPUThread::x) == 8, u32, void>)OFFSET_32(SPUThread, x))
#define SPU_OFF_32(x) asmjit::host::dword_ptr(*cpu, (std::conditional_t<sizeof(SPUThread::x) == 4, u32, void>)OFFSET_32(SPUThread, x))
#define SPU_OFF_16(x) asmjit::host::word_ptr(*cpu, (std::conditional_t<sizeof(SPUThread::x) == 2, u32, void>)OFFSET_32(SPUThread, x))
#define SPU_OFF_8(x) asmjit::host::byte_ptr(*cpu, (std::conditional_t<sizeof(SPUThread::x) == 1, u32, void>)OFFSET_32(SPUThread, x))
const spu_decoder<spu_interpreter_fast> s_spu_interpreter; // TODO: remove
const spu_decoder<spu_recompiler> s_spu_decoder;
@ -345,7 +345,7 @@ void spu_recompiler::FunctionCall()
// Proceed recursively
spu_recompiler_base::enter(*_spu);
if (test(_spu->state & cpu_state::ret))
if (test(_spu->state & cpu_flag::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), static_cast<u16>(cpu_state::stop + cpu_state::ret));
c->lock().or_(SPU_OFF_32(state), static_cast<u32>(cpu_flag::stop + cpu_flag::ret));
c->jmp(*end);
c->unuse(*addr);
return;

View File

@ -24,7 +24,7 @@ void spu_recompiler_base::enter(SPUThread& spu)
// Reset callstack if necessary
if (func->does_reset_stack && spu.recursion_level)
{
spu.state += cpu_state::ret;
spu.state += cpu_flag::ret;
return;
}

View File

@ -237,7 +237,7 @@ SPUThread::~SPUThread()
}
SPUThread::SPUThread(const std::string& name)
: cpu_thread(cpu_type::spu)
: cpu_thread()
, m_name(name)
, index(0)
, offset(0)
@ -245,7 +245,7 @@ SPUThread::SPUThread(const std::string& name)
}
SPUThread::SPUThread(const std::string& name, u32 index)
: cpu_thread(cpu_type::spu)
: cpu_thread()
, m_name(name)
, index(index)
, offset(vm::alloc(0x40000, vm::main))
@ -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(test(state & cpu_state::stop) || channel.try_pop(out)));
thread_lock{*this}, thread_ctrl::wait(WRAP_EXPR(test(state & cpu_flag::stop) || channel.try_pop(out)));
return !test(state & cpu_state::stop);
return !test(state & cpu_flag::stop);
}
return true;
@ -630,7 +630,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
CHECK_EMU_STATUS;
if (test(state & cpu_state::stop))
if (test(state & cpu_flag::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) || test(state & cpu_state::stop)));
vm::wait_op(last_raddr, 128, WRAP_EXPR(get_events(true) || test(state & cpu_flag::stop)));
}
else
{
lock.lock();
// simple waiting loop otherwise
while (!get_events(true) && !test(state & cpu_state::stop))
while (!get_events(true) && !test(state & cpu_flag::stop))
{
CHECK_EMU_STATUS;
@ -719,7 +719,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
ch_event_stat &= ~SPU_EVENT_WAITING;
if (test(state & cpu_state::stop))
if (test(state & cpu_flag::stop))
{
return false;
}
@ -759,7 +759,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
{
CHECK_EMU_STATUS;
if (test(state & cpu_state::stop))
if (test(state & cpu_flag::stop))
{
return false;
}
@ -966,7 +966,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
{
CHECK_EMU_STATUS;
if (test(state & cpu_state::stop))
if (test(state & cpu_flag::stop))
{
return false;
}
@ -1136,7 +1136,7 @@ bool SPUThread::stop_and_signal(u32 code)
});
int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT);
state += cpu_state::stop;
state += cpu_flag::stop;
return true; // ???
}
@ -1150,7 +1150,7 @@ bool SPUThread::stop_and_signal(u32 code)
case 0x002:
{
state += cpu_state::ret;
state += cpu_flag::ret;
return true;
}
@ -1231,7 +1231,7 @@ bool SPUThread::stop_and_signal(u32 code)
{
CHECK_EMU_STATUS;
if (test(state & cpu_state::stop))
if (test(state & cpu_flag::stop))
{
return false;
}
@ -1248,7 +1248,7 @@ bool SPUThread::stop_and_signal(u32 code)
{
if (thread)
{
thread->state += cpu_state::suspend;
thread->state += cpu_flag::suspend;
}
}
}
@ -1268,11 +1268,11 @@ bool SPUThread::stop_and_signal(u32 code)
sleep_entry<cpu_thread> waiter(queue->thread_queue(lv2_lock), *this);
// wait on the event queue
while (!state.test_and_reset(cpu_state::signal))
while (!state.test_and_reset(cpu_flag::signal))
{
CHECK_EMU_STATUS;
if (test(state & cpu_state::stop))
if (test(state & cpu_flag::stop))
{
return false;
}
@ -1301,12 +1301,12 @@ bool SPUThread::stop_and_signal(u32 code)
{
if (thread && thread.get() != this)
{
thread->state -= cpu_state::suspend;
thread->state -= cpu_flag::suspend;
thread->lock_notify();
}
}
state -= cpu_state::suspend;
state -= cpu_flag::suspend;
group->cv.notify_all();
return true;
@ -1340,7 +1340,7 @@ bool SPUThread::stop_and_signal(u32 code)
{
if (thread && thread.get() != this)
{
thread->state += cpu_state::stop;
thread->state += cpu_flag::stop;
thread->lock_notify();
}
}
@ -1350,7 +1350,7 @@ bool SPUThread::stop_and_signal(u32 code)
group->join_state |= SPU_TGJSF_GROUP_EXIT;
group->cv.notify_one();
state += cpu_state::stop;
state += cpu_flag::stop;
return true;
}
@ -1377,7 +1377,7 @@ bool SPUThread::stop_and_signal(u32 code)
status |= SPU_STATUS_STOPPED_BY_STOP;
group->cv.notify_one();
state += cpu_state::stop;
state += cpu_flag::stop;
return true;
}
}
@ -1406,7 +1406,7 @@ void SPUThread::halt()
int_ctrl[2].set(SPU_INT2_STAT_SPU_HALT_OR_STEP_INT);
throw cpu_state::stop;
throw cpu_flag::stop;
}
status |= SPU_STATUS_STOPPED_BY_HALT;
@ -1431,13 +1431,13 @@ void SPUThread::fast_call(u32 ls_addr)
{
cpu_task();
}
catch (cpu_state _s)
catch (cpu_flag _s)
{
state += _s;
if (_s != cpu_state::ret) throw;
if (_s != cpu_flag::ret) throw;
}
state -= cpu_state::ret;
state -= cpu_flag::ret;
pc = old_pc;
gpr[0]._u32[3] = old_lr;

View File

@ -913,7 +913,7 @@ extern void ppu_execute_syscall(ppu_thread& ppu, u64 code)
if (code < g_ppu_syscall_table.size())
{
// If autopause occures, check_status() will hold the thread till unpaused.
if (debug::autopause::pause_syscall(code) && ppu.check_state()) throw cpu_state::ret;
if (debug::autopause::pause_syscall(code) && ppu.check_state()) throw cpu_flag::ret;
if (auto func = g_ppu_syscall_table[code])
{

View File

@ -25,7 +25,7 @@ void lv2_cond_t::notify(lv2_lock_t, cpu_thread* thread)
{
mutex->owner = idm::get<ppu_thread>(thread->id);
VERIFY(!thread->state.test_and_set(cpu_state::signal));
VERIFY(!thread->state.test_and_set(cpu_flag::signal));
thread->notify();
}
}
@ -198,7 +198,7 @@ s32 sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout)
// potential mutex waiter (not added immediately)
sleep_entry<cpu_thread> mutex_waiter(cond->mutex->sq, ppu, defer_sleep);
while (!ppu.state.test_and_reset(cpu_state::signal))
while (!ppu.state.test_and_reset(cpu_flag::signal))
{
CHECK_EMU_STATUS;

View File

@ -61,7 +61,7 @@ void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 d
// notify waiter; protocol is ignored in current implementation
auto& thread = m_sq.front();
if (type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu)
if (type == SYS_PPU_QUEUE && thread->id >= ppu_thread::id_min)
{
// store event data in registers
auto& ppu = static_cast<ppu_thread&>(*thread);
@ -71,7 +71,7 @@ void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 d
ppu.gpr[6] = data2;
ppu.gpr[7] = data3;
}
else if (type == SYS_SPU_QUEUE && thread->type == cpu_type::spu)
else if (type == SYS_SPU_QUEUE && thread->id < ppu_thread::id_min)
{
// store event data in In_MBox
auto& spu = static_cast<SPUThread&>(*thread);
@ -80,10 +80,10 @@ void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 d
}
else
{
fmt::throw_exception("Unexpected (queue type=%d, thread type=%d)" HERE, type, (s32)thread->type);
fmt::throw_exception("Unexpected (queue type=%d, tid=%s)" HERE, type, thread->id);
}
VERIFY(!thread->state.test_and_set(cpu_state::signal));
VERIFY(!thread->state.test_and_set(cpu_flag::signal));
thread->notify();
return m_sq.pop_front();
@ -163,20 +163,20 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode)
// signal all threads to return CELL_ECANCELED
for (auto& thread : queue->thread_queue(lv2_lock))
{
if (queue->type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu)
if (queue->type == SYS_PPU_QUEUE && thread->id >= ppu_thread::id_min)
{
static_cast<ppu_thread&>(*thread).gpr[3] = 1;
}
else if (queue->type == SYS_SPU_QUEUE && thread->type == cpu_type::spu)
else if (queue->type == SYS_SPU_QUEUE && thread->id < ppu_thread::id_min)
{
static_cast<SPUThread&>(*thread).ch_in_mbox.set_values(1, CELL_ECANCELED);
}
else
{
fmt::throw_exception("Unexpected (queue.type=%d, thread.type=%d)" HERE, queue->type, thread->type);
fmt::throw_exception("Unexpected (queue type=%d, tid=%s)" HERE, queue->type, thread->id);
}
thread->state += cpu_state::signal;
thread->state += cpu_flag::signal;
thread->notify();
}
@ -253,7 +253,7 @@ s32 sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_event_t>
// add waiter; protocol is ignored in current implementation
sleep_entry<cpu_thread> waiter(queue->thread_queue(lv2_lock), ppu);
while (!ppu.state.test_and_reset(cpu_state::signal))
while (!ppu.state.test_and_reset(cpu_flag::signal))
{
CHECK_EMU_STATUS;

View File

@ -29,7 +29,7 @@ void lv2_event_flag_t::notify_all(lv2_lock_t)
// save pattern
ppu.gpr[4] = clear_pattern(bitptn, mode);
VERIFY(!thread->state.test_and_set(cpu_state::signal));
VERIFY(!thread->state.test_and_set(cpu_flag::signal));
thread->notify();
return true;
@ -146,7 +146,7 @@ s32 sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr<u
// add waiter; protocol is ignored in current implementation
sleep_entry<cpu_thread> waiter(eflag->sq, ppu);
while (!ppu.state.test_and_reset(cpu_state::signal))
while (!ppu.state.test_and_reset(cpu_flag::signal))
{
CHECK_EMU_STATUS;
@ -292,7 +292,7 @@ s32 sys_event_flag_cancel(u32 id, vm::ptr<u32> num)
// clear "mode" as a sign of cancellation
ppu.gpr[5] = 0;
VERIFY(!thread->state.test_and_set(cpu_state::signal));
VERIFY(!thread->state.test_and_set(cpu_flag::signal));
thread->notify();
}

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 (!test(thread->state & cpu_state::exit))
while (!test(thread->state & cpu_flag::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 (!test(it->state & cpu_state::stop))
if (!test(it->state & cpu_flag::stop))
{
return CELL_EAGAIN;
}
@ -139,13 +139,13 @@ void sys_interrupt_thread_eoi(ppu_thread& ppu) // Low-level PPU function example
// Low-level function body must guard all C++-ish calls and all objects with non-trivial destructors
thread_guard{ppu}, sys_interrupt.trace("sys_interrupt_thread_eoi()");
ppu.state += cpu_state::ret;
ppu.state += cpu_flag::ret;
// Throw if this syscall was not called directly by the SC instruction (hack)
if (ppu.lr == 0 || ppu.gpr[11] != 88)
{
// Low-level function must disable interrupts before throwing (not related to sys_interrupt_*, it's rather coincidence)
ppu->interrupt_disable();
throw cpu_state::ret;
throw cpu_flag::ret;
}
}

View File

@ -30,7 +30,7 @@ void lv2_lwcond_t::notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr<
mutex->signaled--;
}
VERIFY(!thread->state.test_and_set(cpu_state::signal));
VERIFY(!thread->state.test_and_set(cpu_flag::signal));
thread->notify();
}
@ -180,7 +180,7 @@ s32 _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 t
// potential mutex waiter (not added immediately)
sleep_entry<cpu_thread> mutex_waiter(cond->sq, ppu, defer_sleep);
while (!ppu.state.test_and_reset(cpu_state::signal))
while (!ppu.state.test_and_reset(cpu_flag::signal))
{
CHECK_EMU_STATUS;

View File

@ -21,7 +21,7 @@ void lv2_lwmutex_t::unlock(lv2_lock_t)
if (sq.size())
{
auto& thread = sq.front();
VERIFY(!thread->state.test_and_set(cpu_state::signal));
VERIFY(!thread->state.test_and_set(cpu_flag::signal));
thread->notify();
sq.pop_front();
@ -100,7 +100,7 @@ s32 _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
// add waiter; protocol is ignored in current implementation
sleep_entry<cpu_thread> waiter(mutex->sq, ppu);
while (!ppu.state.test_and_reset(cpu_state::signal))
while (!ppu.state.test_and_reset(cpu_flag::signal))
{
CHECK_EMU_STATUS;

View File

@ -20,7 +20,7 @@ void lv2_mutex_t::unlock(lv2_lock_t)
// pick new owner; protocol is ignored in current implementation
owner = idm::get<ppu_thread>(sq.front()->id);
VERIFY(!owner->state.test_and_set(cpu_state::signal));
VERIFY(!owner->state.test_and_set(cpu_flag::signal));
owner->notify();
}
}
@ -135,7 +135,7 @@ s32 sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout)
// add waiter; protocol is ignored in current implementation
sleep_entry<cpu_thread> waiter(mutex->sq, ppu);
while (!ppu.state.test_and_reset(cpu_state::signal))
while (!ppu.state.test_and_reset(cpu_flag::signal))
{
CHECK_EMU_STATUS;

View File

@ -19,7 +19,7 @@ void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode)
LV2_LOCK;
ppu.state += cpu_state::exit;
ppu.state += cpu_flag::exit;
// Delete detached thread
if (!ppu.is_joinable)
@ -30,7 +30,7 @@ void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode)
// Throw if this syscall was not called directly by the SC instruction (hack)
if (ppu.lr == 0 || ppu.gpr[11] != 41)
{
throw cpu_state::exit;
throw cpu_flag::exit;
}
}
@ -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 (!test(thread->state & cpu_state::exit))
while (!test(thread->state & cpu_flag::exit))
{
CHECK_EMU_STATUS;

View File

@ -18,7 +18,7 @@ void lv2_rwlock_t::notify_all(lv2_lock_t)
{
writer = idm::get<ppu_thread>(wsq.front()->id);
VERIFY(!writer->state.test_and_set(cpu_state::signal));
VERIFY(!writer->state.test_and_set(cpu_flag::signal));
writer->notify();
return wsq.pop_front();
@ -31,7 +31,7 @@ void lv2_rwlock_t::notify_all(lv2_lock_t)
for (auto& thread : rsq)
{
VERIFY(!thread->state.test_and_set(cpu_state::signal));
VERIFY(!thread->state.test_and_set(cpu_flag::signal));
thread->notify();
}
@ -118,7 +118,7 @@ s32 sys_rwlock_rlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
// add waiter; protocol is ignored in current implementation
sleep_entry<cpu_thread> waiter(rwlock->rsq, ppu);
while (!ppu.state.test_and_reset(cpu_state::signal))
while (!ppu.state.test_and_reset(cpu_flag::signal))
{
CHECK_EMU_STATUS;
@ -229,7 +229,7 @@ s32 sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
// add waiter; protocol is ignored in current implementation
sleep_entry<cpu_thread> waiter(rwlock->wsq, ppu);
while (!ppu.state.test_and_reset(cpu_state::signal))
while (!ppu.state.test_and_reset(cpu_flag::signal))
{
CHECK_EMU_STATUS;

View File

@ -93,7 +93,7 @@ s32 sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout)
// add waiter; protocol is ignored in current implementation
sleep_entry<cpu_thread> waiter(sem->sq, ppu);
while (!ppu.state.test_and_reset(cpu_state::signal))
while (!ppu.state.test_and_reset(cpu_flag::signal))
{
CHECK_EMU_STATUS;
@ -173,7 +173,7 @@ s32 sys_semaphore_post(u32 sem_id, s32 count)
count--;
auto& thread = sem->sq.front();
VERIFY(!thread->state.test_and_set(cpu_state::signal));
VERIFY(!thread->state.test_and_set(cpu_flag::signal));
thread->notify();
sem->sq.pop_front();

View File

@ -374,7 +374,7 @@ s32 sys_spu_thread_group_suspend(u32 id)
{
if (thread)
{
thread->state += cpu_state::suspend;
thread->state += cpu_flag::suspend;
}
}
@ -418,7 +418,7 @@ s32 sys_spu_thread_group_resume(u32 id)
{
if (thread)
{
thread->state -= cpu_state::suspend;
thread->state -= cpu_flag::suspend;
thread->lock_notify();
}
}
@ -501,7 +501,7 @@ s32 sys_spu_thread_group_terminate(u32 id, s32 value)
{
if (thread)
{
thread->state += cpu_state::stop;
thread->state += cpu_flag::stop;
thread->lock_notify();
}
}
@ -1169,7 +1169,7 @@ s32 sys_raw_spu_destroy(ppu_thread& ppu, u32 id)
// TODO: CELL_EBUSY is not returned
// Stop thread
thread->state += cpu_state::stop;
thread->state += cpu_flag::stop;
// Clear interrupt handlers
for (auto& intr : thread->int_ctrl)

View File

@ -817,127 +817,6 @@ namespace vm
g_locations.clear();
}
u32 stack_push(u32 size, u32 align_v)
{
if (auto cpu = get_current_cpu_thread()) switch (cpu->type)
{
case cpu_type::ppu:
{
ppu_thread& context = static_cast<ppu_thread&>(*cpu);
const u32 old_pos = vm::cast(context.gpr[1], HERE);
context.gpr[1] -= align(size + 4, 8); // room minimal possible size
context.gpr[1] &= ~(align_v - 1); // fix stack alignment
if (context.gpr[1] < context.stack_addr)
{
fmt::throw_exception("Stack overflow (size=0x%x, align=0x%x, SP=0x%llx, stack=*0x%x)" HERE, size, align_v, old_pos, context.stack_addr);
}
else
{
const u32 addr = static_cast<u32>(context.gpr[1]);
vm::ps3::_ref<nse_t<u32>>(addr + size) = old_pos;
std::memset(vm::base(addr), 0, size);
return addr;
}
}
case cpu_type::spu:
{
SPUThread& context = static_cast<SPUThread&>(*cpu);
const u32 old_pos = context.gpr[1]._u32[3];
context.gpr[1]._u32[3] -= align(size + 4, 16);
context.gpr[1]._u32[3] &= ~(align_v - 1);
if (context.gpr[1]._u32[3] >= 0x40000) // extremely rough
{
fmt::throw_exception("Stack overflow (size=0x%x, align=0x%x, SP=LS:0x%05x)" HERE, size, align_v, old_pos);
}
else
{
const u32 addr = context.gpr[1]._u32[3] + context.offset;
vm::ps3::_ref<nse_t<u32>>(addr + size) = old_pos;
return addr;
}
}
case cpu_type::arm:
{
ARMv7Thread& context = static_cast<ARMv7Thread&>(*cpu);
const u32 old_pos = context.SP;
context.SP -= align(size + 4, 4); // room minimal possible size
context.SP &= ~(align_v - 1); // fix stack alignment
if (context.SP < context.stack_addr)
{
fmt::throw_exception("Stack overflow (size=0x%x, align=0x%x, SP=0x%x, stack=*0x%x)" HERE, size, align_v, context.SP, context.stack_addr);
}
else
{
vm::psv::_ref<nse_t<u32>>(context.SP + size) = old_pos;
return context.SP;
}
}
default:
{
fmt::throw_exception("Invalid thread type (%u)" HERE, cpu->type);
}
}
fmt::throw_exception("Invalid thread" HERE);
}
void stack_pop_verbose(u32 addr, u32 size) noexcept
{
if (auto cpu = get_current_cpu_thread()) switch (cpu->type)
{
case cpu_type::ppu:
{
ppu_thread& context = static_cast<ppu_thread&>(*cpu);
if (context.gpr[1] != addr)
{
LOG_ERROR(MEMORY, "Stack inconsistency (addr=0x%x, SP=0x%llx, size=0x%x)", addr, context.gpr[1], size);
return;
}
context.gpr[1] = vm::ps3::_ref<nse_t<u32>>(context.gpr[1] + size);
return;
}
case cpu_type::spu:
{
SPUThread& context = static_cast<SPUThread&>(*cpu);
if (context.gpr[1]._u32[3] + context.offset != addr)
{
LOG_ERROR(MEMORY, "Stack inconsistency (addr=0x%x, SP=LS:0x%05x, size=0x%x)", addr, context.gpr[1]._u32[3], size);
return;
}
context.gpr[1]._u32[3] = vm::ps3::_ref<nse_t<u32>>(context.gpr[1]._u32[3] + context.offset + size);
return;
}
case cpu_type::arm:
{
ARMv7Thread& context = static_cast<ARMv7Thread&>(*cpu);
if (context.SP != addr)
{
LOG_ERROR(MEMORY, "Stack inconsistency (addr=0x%x, SP=0x%x, size=0x%x)", addr, context.SP, size);
return;
}
context.SP = vm::psv::_ref<nse_t<u32>>(context.SP + size);
return;
}
}
}
[[noreturn]] void throw_access_violation(u64 addr, const char* cause)
{
throw access_violation(addr, cause);

View File

@ -360,9 +360,6 @@ namespace vm
void close();
u32 stack_push(u32 size, u32 align_v);
void stack_pop_verbose(u32 addr, u32 size) noexcept;
extern thread_local u64 g_tls_fault_count;
}

View File

@ -18,16 +18,17 @@ namespace vm
}
};
template<typename T>
struct stack_allocator
{
static inline vm::addr_t alloc(u32 size, u32 align)
{
return vm::cast(vm::stack_push(size, align));
return vm::cast(T::stack_push(size, align));
}
static inline void dealloc(u32 addr, u32 size) noexcept
{
vm::stack_pop_verbose(addr, size);
T::stack_pop_verbose(addr, size);
}
};
@ -98,21 +99,30 @@ namespace vm
};
// LE variable
template<typename T, typename A = stack_allocator> using varl = _var_base<to_le_t<T>, A>;
template<typename T, typename A> using varl = _var_base<to_le_t<T>, A>;
// BE variable
template<typename T, typename A = stack_allocator> using varb = _var_base<to_be_t<T>, A>;
template<typename T, typename A> using varb = _var_base<to_be_t<T>, A>;
namespace ps3
{
// BE variable
template<typename T, typename A = stack_allocator> using var = varb<T, A>;
template<typename T, typename A = stack_allocator<ppu_thread>> using var = varb<T, A>;
// Make BE variable initialized from value
template<typename T>
template<typename T, typename A = stack_allocator<ppu_thread>>
inline auto make_var(const T& value)
{
return varb<T>(value);
return varb<T, A>(value);
}
// Make char[] variable initialized from std::string
template<typename A = stack_allocator<ppu_thread>>
static auto make_str(const std::string& str)
{
var<char[], A> var_(size32(str) + 1);
std::memcpy(var_.get_ptr(), str.c_str(), str.size() + 1);
return var_;
}
// Global HLE variable
@ -125,13 +135,22 @@ namespace vm
namespace psv
{
// LE variable
template<typename T, typename A = stack_allocator> using var = varl<T, A>;
template<typename T, typename A = stack_allocator<ARMv7Thread>> using var = varl<T, A>;
// Make LE variable initialized from value
template<typename T>
template<typename T, typename A = stack_allocator<ARMv7Thread>>
inline auto make_var(const T& value)
{
return varl<T>(value);
return var<T, A>(value);
}
// Make char[] variable initialized from std::string
template<typename A = stack_allocator<ARMv7Thread>>
static auto make_str(const std::string& str)
{
var<char[], A> var_(size32(str) + 1);
std::memcpy(var_.get_ptr(), str.c_str(), str.size() + 1);
return var_;
}
// Global HLE variable
@ -140,12 +159,4 @@ namespace vm
{
};
}
// Make char[] variable initialized from std::string
static auto make_str(const std::string& str)
{
_var_base<char[], stack_allocator> var(size32(str) + 1);
std::memcpy(var.get_ptr(), str.c_str(), str.size() + 1);
return var;
}
}

View File

@ -39,22 +39,19 @@ s32 arm_error_code::report(s32 error, const char* text)
{
if (auto thread = get_current_cpu_thread())
{
if (thread->type == cpu_type::arm)
if (auto func = static_cast<ARMv7Thread*>(thread)->last_function)
{
if (auto func = static_cast<ARMv7Thread*>(thread)->last_function)
{
LOG_ERROR(ARMv7, "Function '%s' failed with 0x%08x : %s", func, error, text);
}
else
{
LOG_ERROR(ARMv7, "Unknown function failed with 0x%08x : %s", error, text);
}
return error;
LOG_ERROR(ARMv7, "Function '%s' failed with 0x%08x : %s", func, error, text);
}
else
{
LOG_ERROR(ARMv7, "Unknown function failed with 0x%08x : %s", error, text);
}
return error;
}
LOG_ERROR(ARMv7, "Illegal call to ppu_report_error(0x%x, '%s')!");
LOG_ERROR(ARMv7, "Illegal call to arm_report_error(0x%x, '%s')!");
return error;
}
@ -63,7 +60,7 @@ std::vector<arm_function_t>& arm_function_manager::access()
static std::vector<arm_function_t> list
{
nullptr,
[](ARMv7Thread& cpu) { cpu.state += cpu_state::ret; },
[](ARMv7Thread& cpu) { cpu.state += cpu_flag::ret; },
};
return list;

View File

@ -120,7 +120,7 @@ ARMv7Thread::~ARMv7Thread()
}
ARMv7Thread::ARMv7Thread(const std::string& name)
: cpu_thread(cpu_type::arm)
: cpu_thread()
, m_name(name)
{
}
@ -142,15 +142,15 @@ void ARMv7Thread::fast_call(u32 addr)
{
cpu_task_main();
if (SP != old_SP && !test(state, cpu_state::ret + cpu_state::exit)) // SP shouldn't change
if (SP != old_SP && !test(state, cpu_flag::ret + cpu_flag::exit)) // SP shouldn't change
{
fmt::throw_exception("Stack inconsistency (addr=0x%x, SP=0x%x, old=0x%x)", addr, SP, old_SP);
}
}
catch (cpu_state _s)
catch (cpu_flag _s)
{
state += _s;
if (_s != cpu_state::ret) throw;
if (_s != cpu_flag::ret) throw;
}
catch (EmulationStopped)
{
@ -165,7 +165,7 @@ void ARMv7Thread::fast_call(u32 addr)
throw;
}
state -= cpu_state::ret;
state -= cpu_flag::ret;
PC = old_PC;
SP = old_SP;
@ -173,3 +173,46 @@ void ARMv7Thread::fast_call(u32 addr)
custom_task = std::move(old_task);
last_function = old_func;
}
u32 ARMv7Thread::stack_push(u32 size, u32 align_v)
{
if (auto cpu = get_current_cpu_thread())
{
ARMv7Thread& context = static_cast<ARMv7Thread&>(*cpu);
const u32 old_pos = context.SP;
context.SP -= align(size + 4, 4); // room minimal possible size
context.SP &= ~(align_v - 1); // fix stack alignment
if (context.SP < context.stack_addr)
{
fmt::throw_exception("Stack overflow (size=0x%x, align=0x%x, SP=0x%x, stack=*0x%x)" HERE, size, align_v, context.SP, context.stack_addr);
}
else
{
vm::psv::_ref<nse_t<u32>>(context.SP + size) = old_pos;
return context.SP;
}
}
fmt::throw_exception("Invalid thread" HERE);
}
void ARMv7Thread::stack_pop_verbose(u32 addr, u32 size) noexcept
{
if (auto cpu = get_current_cpu_thread())
{
ARMv7Thread& context = static_cast<ARMv7Thread&>(*cpu);
if (context.SP != addr)
{
LOG_ERROR(ARMv7, "Stack inconsistency (addr=0x%x, SP=0x%x, size=0x%x)", addr, context.SP, size);
return;
}
context.SP = vm::psv::_ref<nse_t<u32>>(context.SP + size);
return;
}
LOG_ERROR(ARMv7, "Invalid thread" HERE);
}

View File

@ -196,6 +196,9 @@ public:
}
void fast_call(u32 addr);
static u32 stack_push(u32 size, u32 align_v);
static void stack_pop_verbose(u32 addr, u32 size) noexcept;
};
template<typename T, typename = void>

View File

@ -138,7 +138,7 @@ arm_error_code sceKernelExitThread(ARMv7Thread& cpu, s32 exitStatus)
sceLibKernel.warning("sceKernelExitThread(exitStatus=0x%x)", exitStatus);
// Exit status is stored in r0
cpu.state += cpu_state::exit;
cpu.state += cpu_flag::exit;
return SCE_OK;
}
@ -170,7 +170,7 @@ arm_error_code sceKernelExitDeleteThread(ARMv7Thread& cpu, s32 exitStatus)
{
sceLibKernel.warning("sceKernelExitDeleteThread(exitStatus=0x%x)", exitStatus);
//cpu.state += cpu_state::stop;
//cpu.state += cpu_flag::stop;
// Delete current thread; exit status is stored in r0
fxm::get<arm_tls_manager>()->free(cpu.TLS);
@ -517,7 +517,7 @@ struct psp2_event_flag final
{
idm::get<ARMv7Thread>(cmd.arg, [&](u32, ARMv7Thread& cpu)
{
cpu.state += cpu_state::signal;
cpu.state += cpu_flag::signal;
cpu.lock_notify();
});
@ -545,11 +545,11 @@ struct psp2_event_flag final
{
if (!exec(task::signal, cpu.id))
{
thread_lock{cpu}, thread_ctrl::wait(WRAP_EXPR(cpu.state.test_and_reset(cpu_state::signal)));
thread_lock{cpu}, thread_ctrl::wait(WRAP_EXPR(cpu.state.test_and_reset(cpu_flag::signal)));
}
else
{
cpu.state -= cpu_state::signal;
cpu.state -= cpu_flag::signal;
}
}
}
@ -579,7 +579,7 @@ private:
{
cpu.GPR[0] = SCE_OK;
cpu.GPR[1] = pattern;
cpu.state += cpu_state::signal;
cpu.state += cpu_flag::signal;
cpu->lock_notify();
}
else
@ -679,7 +679,7 @@ private:
{
cpu.GPR[0] = SCE_OK;
cpu.GPR[1] = old_pattern;
cpu.state += cpu_state::signal;
cpu.state += cpu_flag::signal;
cpu.owner = nullptr;
cpu->unlock();
cpu->notify();
@ -713,7 +713,7 @@ private:
{
cpu.GPR[0] = error;
cpu.GPR[1] = pattern;
cpu.state += cpu_state::signal;
cpu.state += cpu_flag::signal;
cpu.owner = nullptr;
cpu->unlock();
cpu->notify();
@ -858,7 +858,7 @@ arm_error_code sceKernelWaitEventFlag(ARMv7Thread& cpu, s32 evfId, u32 bitPatter
cpu.GPR[1] = bitPattern;
// Second chance
if (evf->exec(psp2_event_flag::task::wait, cpu.id) && cpu.state.test_and_reset(cpu_state::signal))
if (evf->exec(psp2_event_flag::task::wait, cpu.id) && cpu.state.test_and_reset(cpu_flag::signal))
{
if (pResultPat) *pResultPat = cpu.GPR[1];
return SCE_OK;
@ -866,7 +866,7 @@ arm_error_code sceKernelWaitEventFlag(ARMv7Thread& cpu, s32 evfId, u32 bitPatter
thread_lock entry(cpu);
if (!thread_ctrl::wait_for(timeout, WRAP_EXPR(cpu.state.test_and_reset(cpu_state::signal))))
if (!thread_ctrl::wait_for(timeout, WRAP_EXPR(cpu.state.test_and_reset(cpu_flag::signal))))
{
// Timeout cleanup
cpu.owner = nullptr;

View File

@ -25,6 +25,8 @@
#include <thread>
system_type g_system;
cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot", true);
cfg::bool_entry g_cfg_autoexit(cfg::root.misc, "Exit RPCS3 when process finishes");
@ -208,6 +210,7 @@ void Emulator::Load()
else if (ppu_exec.open(elf_file) == elf_error::ok)
{
// PS3 executable
g_system = system_type::ps3;
m_status = Ready;
vm::ps3::init();
@ -276,6 +279,7 @@ void Emulator::Load()
else if (ppu_prx.open(elf_file) == elf_error::ok)
{
// PPU PRX (experimental)
g_system = system_type::ps3;
m_status = Ready;
vm::ps3::init();
ppu_load_prx(ppu_prx);
@ -283,6 +287,7 @@ void Emulator::Load()
else if (spu_exec.open(elf_file) == elf_error::ok)
{
// SPU executable (experimental)
g_system = system_type::ps3;
m_status = Ready;
vm::ps3::init();
spu_load_exec(spu_exec);
@ -290,6 +295,7 @@ void Emulator::Load()
else if (arm_exec.open(elf_file) == elf_error::ok)
{
// ARMv7 executable
g_system = system_type::psv;
m_status = Ready;
vm::psv::init();
arm_load_exec(arm_exec);
@ -370,7 +376,7 @@ bool Emulator::Pause()
idm::select<ppu_thread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
{
cpu.state += cpu_state::dbg_global_pause;
cpu.state += cpu_flag::dbg_global_pause;
});
SendDbgCommand(DID_PAUSED_EMU);
@ -404,7 +410,7 @@ void Emulator::Resume()
idm::select<ppu_thread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
{
cpu.state -= cpu_state::dbg_global_pause;
cpu.state -= cpu_flag::dbg_global_pause;
cpu.lock_notify();
});
@ -430,7 +436,7 @@ void Emulator::Stop()
idm::select<ppu_thread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
{
cpu.state += cpu_state::dbg_global_stop;
cpu.state += cpu_flag::dbg_global_stop;
cpu->lock();
cpu->set_exception(std::make_exception_ptr(EmulationStopped()));
cpu->unlock();

View File

@ -3,6 +3,16 @@
#include "VFS.h"
#include "DbgCommand.h"
enum class system_type
{
ps3,
psv, // Experimental
//psp, // Hypothetical
};
// Current process type
extern system_type g_system;
enum class frame_type;
struct EmuCallbacks

View File

@ -1,8 +1,10 @@
#include "stdafx.h"
#include "stdafx_gui.h"
#include "Emu/System.h"
#include "Emu/Memory/Memory.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/CPU/CPUDisAsm.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h"
#include "InstructionEditor.h"
@ -59,7 +61,7 @@ InstructionEditorDialog::InstructionEditorDialog(wxPanel *parent, u32 _pc, cpu_t
s_panel_margin_x->Add(s_panel_margin_y);
s_panel_margin_x->AddSpacer(12);
const u32 cpu_offset = cpu->type == cpu_type::spu ? static_cast<SPUThread&>(*cpu).offset : 0;
const u32 cpu_offset = g_system == system_type::ps3 && cpu->id < ppu_thread::id_min ? static_cast<SPUThread&>(*cpu).offset : 0;
this->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(InstructionEditorDialog::updatePreview));
t2_instr->SetValue(wxString::Format("%08x", vm::ps3::read32(cpu_offset + pc).value()));
@ -81,7 +83,7 @@ void InstructionEditorDialog::updatePreview(wxCommandEvent& event)
ulong opcode;
if (t2_instr->GetValue().ToULong(&opcode, 16))
{
if (cpu->type == cpu_type::arm)
if (g_system == system_type::psv)
{
t3_preview->SetLabel("Preview for ARMv7Thread not implemented yet.");
}

View File

@ -23,11 +23,10 @@ std::map<u32, bool> g_breakpoints;
u32 InterpreterDisAsmFrame::GetPc() const
{
switch (cpu->type)
switch (g_system)
{
case cpu_type::ppu: return static_cast<ppu_thread*>(cpu)->cia;
case cpu_type::spu: return static_cast<SPUThread*>(cpu)->pc;
case cpu_type::arm: return static_cast<ARMv7Thread*>(cpu)->PC;
case system_type::ps3: return cpu->id >= ppu_thread::id_min ? static_cast<ppu_thread*>(cpu)->cia : static_cast<SPUThread*>(cpu)->pc;
case system_type::psv: return static_cast<ARMv7Thread*>(cpu)->PC;
}
return 0xabadcafe;
@ -137,21 +136,23 @@ void InterpreterDisAsmFrame::OnSelectUnit(wxCommandEvent& event)
if (cpu = (cpu_thread*)event.GetClientData())
{
switch (cpu->type)
switch (g_system)
{
case cpu_type::ppu:
case system_type::ps3:
{
m_disasm = std::make_unique<PPUDisAsm>(CPUDisAsm_InterpreterMode);
if (cpu->id >= ppu_thread::id_min)
{
m_disasm = std::make_unique<PPUDisAsm>(CPUDisAsm_InterpreterMode);
}
else
{
m_disasm = std::make_unique<SPUDisAsm>(CPUDisAsm_InterpreterMode);
}
break;
}
case cpu_type::spu:
{
m_disasm = std::make_unique<SPUDisAsm>(CPUDisAsm_InterpreterMode);
break;
}
case cpu_type::arm:
case system_type::psv:
{
m_disasm = std::make_unique<ARMv7DisAsm>(CPUDisAsm_InterpreterMode);
break;
@ -249,7 +250,7 @@ void InterpreterDisAsmFrame::ShowAddr(u32 addr)
}
else
{
const u32 cpu_offset = cpu->type == cpu_type::spu ? static_cast<SPUThread&>(*cpu).offset : 0;
const u32 cpu_offset = g_system == system_type::ps3 && cpu->id < ppu_thread::id_min ? static_cast<SPUThread&>(*cpu).offset : 0;
m_disasm->offset = (u8*)vm::base(cpu_offset);
for (uint i = 0, count = 4; i<m_item_count; ++i, m_pc += count)
{
@ -438,7 +439,7 @@ void InterpreterDisAsmFrame::DoRun(wxCommandEvent& WXUNUSED(event))
{
if (cpu && test(cpu->state & cpu_state_pause))
{
cpu->state -= cpu_state::dbg_pause;
cpu->state -= cpu_flag::dbg_pause;
(*cpu)->lock_notify();
}
}
@ -447,7 +448,7 @@ void InterpreterDisAsmFrame::DoPause(wxCommandEvent& WXUNUSED(event))
{
if (cpu)
{
cpu->state += cpu_state::dbg_pause;
cpu->state += cpu_flag::dbg_pause;
}
}
@ -455,10 +456,10 @@ void InterpreterDisAsmFrame::DoStep(wxCommandEvent& WXUNUSED(event))
{
if (cpu)
{
if (test(cpu_state::dbg_pause, cpu->state.fetch_op([](bs_t<cpu_state>& state)
if (test(cpu_flag::dbg_pause, cpu->state.fetch_op([](bs_t<cpu_flag>& state)
{
state += cpu_state::dbg_step;
state -= cpu_state::dbg_pause;
state += cpu_flag::dbg_step;
state -= cpu_flag::dbg_pause;
})))
{
(*cpu)->lock_notify();

View File

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "stdafx_gui.h"
#include "Emu/System.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/CPU/CPUDisAsm.h"
#include "Emu/Cell/PPUThread.h"
@ -53,22 +54,28 @@ RegisterEditorDialog::RegisterEditorDialog(wxPanel *parent, u32 _pc, cpu_thread*
Bind(wxEVT_COMBOBOX, &RegisterEditorDialog::updateRegister, this);
switch (cpu->type)
switch (g_system)
{
case cpu_type::ppu:
for (int i = 0; i<32; i++) t1_register->Append(wxString::Format("GPR[%d]", i));
for (int i = 0; i<32; i++) t1_register->Append(wxString::Format("FPR[%d]", i));
for (int i = 0; i<32; i++) t1_register->Append(wxString::Format("VR[%d]", i));
t1_register->Append("CR");
t1_register->Append("LR");
t1_register->Append("CTR");
//t1_register->Append("XER");
//t1_register->Append("FPSCR");
break;
case system_type::ps3:
{
if (_cpu->id >= ppu_thread::id_min)
{
for (int i = 0; i < 32; i++) t1_register->Append(wxString::Format("GPR[%d]", i));
for (int i = 0; i < 32; i++) t1_register->Append(wxString::Format("FPR[%d]", i));
for (int i = 0; i < 32; i++) t1_register->Append(wxString::Format("VR[%d]", i));
t1_register->Append("CR");
t1_register->Append("LR");
t1_register->Append("CTR");
//t1_register->Append("XER");
//t1_register->Append("FPSCR");
}
else
{
for (int i = 0; i < 128; i++) t1_register->Append(wxString::Format("GPR[%d]", i));
}
case cpu_type::spu:
for (int i = 0; i<128; i++) t1_register->Append(wxString::Format("GPR[%d]", i));
break;
}
default:
wxMessageBox("Not supported thread.", "Error");
@ -82,33 +89,28 @@ RegisterEditorDialog::RegisterEditorDialog(wxPanel *parent, u32 _pc, cpu_thread*
std::string reg = fmt::ToUTF8(t1_register->GetStringSelection());
std::string value = fmt::ToUTF8(t2_value->GetValue());
switch (cpu->type)
{
case cpu_type::ppu:
if (g_system == system_type::ps3 && cpu->id >= ppu_thread::id_min)
{
auto& ppu = *static_cast<ppu_thread*>(cpu);
while (value.length() < 32) value = "0" + value;
std::string::size_type first_brk = reg.find('[');
const auto first_brk = reg.find('[');
try
{
if (first_brk != std::string::npos)
if (first_brk != -1)
{
long reg_index = atol(reg.substr(first_brk + 1, reg.length() - first_brk - 2).c_str());
const long reg_index = std::atol(reg.substr(first_brk + 1, reg.length() - first_brk - 2).c_str());
if (reg.find("GPR") == 0 || reg.find("FPR") == 0)
{
unsigned long long reg_value;
reg_value = std::stoull(value.substr(16, 31), 0, 16);
const ullong reg_value = std::stoull(value.substr(16, 31), 0, 16);
if (reg.find("GPR") == 0) ppu.gpr[reg_index] = (u64)reg_value;
if (reg.find("FPR") == 0) (u64&)ppu.fpr[reg_index] = (u64)reg_value;
return;
}
if (reg.find("VR") == 0)
{
unsigned long long reg_value0;
unsigned long long reg_value1;
reg_value0 = std::stoull(value.substr(16, 31), 0, 16);
reg_value1 = std::stoull(value.substr(0, 15), 0, 16);
const ullong reg_value0 = std::stoull(value.substr(16, 31), 0, 16);
const ullong reg_value1 = std::stoull(value.substr(0, 15), 0, 16);
ppu.vr[reg_index]._u64[0] = (u64)reg_value0;
ppu.vr[reg_index]._u64[1] = (u64)reg_value1;
return;
@ -116,58 +118,46 @@ RegisterEditorDialog::RegisterEditorDialog(wxPanel *parent, u32 _pc, cpu_thread*
}
if (reg == "LR" || reg == "CTR")
{
unsigned long long reg_value;
reg_value = std::stoull(value.substr(16, 31), 0, 16);
const ullong reg_value = std::stoull(value.substr(16, 31), 0, 16);
if (reg == "LR") ppu.lr = (u64)reg_value;
if (reg == "CTR") ppu.ctr = (u64)reg_value;
return;
}
if (reg == "CR")
{
unsigned long long reg_value;
reg_value = std::stoull(value.substr(24, 31), 0, 16);
const ullong reg_value = std::stoull(value.substr(24, 31), 0, 16);
if (reg == "CR") ppu.cr_unpack((u32)reg_value);
return;
}
}
catch (std::invalid_argument&)//if any of the stoull conversion fail
catch (std::invalid_argument&) //if any of the stoull conversion fail
{
break;
}
break;
}
case cpu_type::spu:
else if (g_system == system_type::ps3 && cpu->id < ppu_thread::id_min)
{
auto& spu = *static_cast<SPUThread*>(cpu);
while (value.length() < 32) value = "0" + value;
std::string::size_type first_brk = reg.find('[');
if (first_brk != std::string::npos)
const auto first_brk = reg.find('[');
try
{
long reg_index;
reg_index = atol(reg.substr(first_brk + 1, reg.length() - 2).c_str());
if (reg.find("GPR") == 0)
if (first_brk != -1)
{
ullong reg_value0;
ullong reg_value1;
try
const long reg_index = std::atol(reg.substr(first_brk + 1, reg.length() - 2).c_str());
if (reg.find("GPR") == 0)
{
reg_value0 = std::stoull(value.substr(16, 31), 0, 16);
reg_value1 = std::stoull(value.substr(0, 15), 0, 16);
const ullong reg_value0 = std::stoull(value.substr(16, 31), 0, 16);
const ullong reg_value1 = std::stoull(value.substr(0, 15), 0, 16);
spu.gpr[reg_index]._u64[0] = (u64)reg_value0;
spu.gpr[reg_index]._u64[1] = (u64)reg_value1;
return;
}
catch (std::invalid_argument& /*e*/)
{
break;
}
spu.gpr[reg_index]._u64[0] = (u64)reg_value0;
spu.gpr[reg_index]._u64[1] = (u64)reg_value1;
return;
}
}
break;
}
catch (std::invalid_argument&)
{
}
}
wxMessageBox("This value could not be converted.\nNo changes were made.", "Error");
@ -179,9 +169,7 @@ void RegisterEditorDialog::updateRegister(wxCommandEvent& event)
std::string reg = fmt::ToUTF8(t1_register->GetStringSelection());
std::string str;
switch (cpu->type)
{
case cpu_type::ppu:
if (g_system == system_type::ps3 && cpu->id >= ppu_thread::id_min)
{
auto& ppu = *static_cast<ppu_thread*>(cpu);
@ -196,9 +184,8 @@ void RegisterEditorDialog::updateRegister(wxCommandEvent& event)
if (reg == "CR") str = fmt::format("%08x", ppu.cr_pack());
if (reg == "LR") str = fmt::format("%016llx", ppu.lr);
if (reg == "CTR") str = fmt::format("%016llx", ppu.ctr);
break;
}
case cpu_type::spu:
else if (g_system == system_type::ps3 && cpu->id < ppu_thread::id_min)
{
auto& spu = *static_cast<SPUThread*>(cpu);
@ -209,8 +196,6 @@ void RegisterEditorDialog::updateRegister(wxCommandEvent& event)
reg_index = atol(reg.substr(first_brk + 1, reg.length() - 2).c_str());
if (reg.find("GPR") == 0) str = fmt::format("%016llx%016llx", spu.gpr[reg_index]._u64[1], spu.gpr[reg_index]._u64[0]);
}
break;
}
}
t2_value->SetValue(fmt::FromUTF8(str));