mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
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:
parent
009ac37a7d
commit
bdeccd889f
@ -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
|
||||
|
@ -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...>
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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{};
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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])
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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])
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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.");
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user