2012-11-15 00:39:56 +01:00
|
|
|
#include "stdafx.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/Memory/Memory.h"
|
|
|
|
|
#include "Emu/System.h"
|
2015-10-24 20:48:07 +02:00
|
|
|
#include "Emu/state.h"
|
2015-07-01 00:25:52 +02:00
|
|
|
#include "Emu/IdManager.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
#include "Emu/Cell/PPUThread.h"
|
|
|
|
|
#include "Emu/Cell/PPUDecoder.h"
|
|
|
|
|
#include "Emu/Cell/PPUInterpreter.h"
|
2015-03-16 22:38:21 +01:00
|
|
|
#include "Emu/Cell/PPUInterpreter2.h"
|
2014-08-31 13:10:33 +02:00
|
|
|
#include "Emu/Cell/PPULLVMRecompiler.h"
|
2014-11-19 15:16:30 +01:00
|
|
|
//#include "Emu/Cell/PPURecompiler.h"
|
2015-08-26 17:18:01 +02:00
|
|
|
#include "Utilities/VirtualMemory.h"
|
2014-07-12 23:06:43 +02:00
|
|
|
|
2015-03-16 22:38:21 +01:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
#include <Windows.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-01-08 23:17:26 +01:00
|
|
|
u64 rotate_mask[64][64];
|
|
|
|
|
|
2015-01-30 21:01:13 +01:00
|
|
|
extern u32 ppu_get_tls(u32 thread);
|
|
|
|
|
extern void ppu_free_tls(u32 thread);
|
|
|
|
|
|
2015-08-21 13:07:31 +02:00
|
|
|
//thread_local const std::weak_ptr<ppu_decoder_cache_t> g_tls_ppu_decoder_cache = fxm::get<ppu_decoder_cache_t>();
|
|
|
|
|
thread_local const ppu_decoder_cache_t* g_tls_ppu_decoder_cache = nullptr; // temporarily, because thread_local is not fully available
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2015-08-10 21:39:52 +02:00
|
|
|
ppu_decoder_cache_t::ppu_decoder_cache_t()
|
2015-08-26 17:18:01 +02:00
|
|
|
: pointer(static_cast<decltype(pointer)>(memory_helper::reserve_memory(0x200000000)))
|
2015-08-10 21:39:52 +02:00
|
|
|
{
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2015-08-10 21:39:52 +02:00
|
|
|
ppu_decoder_cache_t::~ppu_decoder_cache_t()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2015-08-26 17:18:01 +02:00
|
|
|
memory_helper::free_reserved_memory(pointer, 0x200000000);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2015-08-10 21:39:52 +02:00
|
|
|
void ppu_decoder_cache_t::initialize(u32 addr, u32 size)
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2015-08-26 17:18:01 +02:00
|
|
|
memory_helper::commit_page_memory(pointer + addr / 4, size * 2);
|
2015-03-16 22:38:21 +01:00
|
|
|
|
|
|
|
|
PPUInterpreter2* inter;
|
|
|
|
|
PPUDecoder dec(inter = new PPUInterpreter2);
|
|
|
|
|
|
|
|
|
|
for (u32 pos = addr; pos < addr + size; pos += 4)
|
|
|
|
|
{
|
2015-03-17 21:03:24 +01:00
|
|
|
inter->func = ppu_interpreter::NULL_OP;
|
2015-03-16 22:38:21 +01:00
|
|
|
|
|
|
|
|
// decode PPU opcode
|
2015-09-14 18:32:35 +02:00
|
|
|
dec.Decode(vm::ps3::read32(pos));
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2015-08-10 21:39:52 +02:00
|
|
|
// store function address
|
|
|
|
|
pointer[pos / 4] = inter->func;
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
PPUThread::PPUThread(const std::string& name)
|
2015-11-26 09:06:29 +01:00
|
|
|
: CPUThread(CPU_THREAD_PPU, name)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-03-16 22:38:21 +01:00
|
|
|
InitRotateMask();
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PPUThread::~PPUThread()
|
|
|
|
|
{
|
2015-07-19 13:36:32 +02:00
|
|
|
close_stack();
|
2015-07-01 00:25:52 +02:00
|
|
|
ppu_free_tls(m_id);
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
std::string PPUThread::get_name() const
|
|
|
|
|
{
|
|
|
|
|
return fmt::format("PPU Thread[0x%x] (%s)[0x%08x]", m_id, CPUThread::get_name(), PC);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-19 13:36:32 +02:00
|
|
|
void PPUThread::dump_info() const
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-09-14 18:32:35 +02:00
|
|
|
extern std::string get_ps3_function_name(u64 fid);
|
|
|
|
|
|
2015-07-03 18:07:36 +02:00
|
|
|
if (~hle_code < 1024)
|
2015-07-01 00:25:52 +02:00
|
|
|
{
|
2015-09-14 18:32:35 +02:00
|
|
|
LOG_SUCCESS(HLE, "Last syscall: %lld (%s)", ~hle_code, get_ps3_function_name(hle_code));
|
2015-07-01 00:25:52 +02:00
|
|
|
}
|
2015-07-08 17:01:59 +02:00
|
|
|
else if (hle_code)
|
2015-07-01 00:25:52 +02:00
|
|
|
{
|
2015-09-14 18:32:35 +02:00
|
|
|
LOG_SUCCESS(HLE, "Last function: %s (0x%llx)", get_ps3_function_name(hle_code), hle_code);
|
2015-07-01 00:25:52 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-19 13:36:32 +02:00
|
|
|
CPUThread::dump_info();
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-19 13:36:32 +02:00
|
|
|
void PPUThread::init_regs()
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-07-01 00:25:52 +02:00
|
|
|
GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200;
|
|
|
|
|
GPR[13] = ppu_get_tls(m_id) + 0x7000; // 0x7000 is subtracted from r13 to access first TLS element
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-02-17 16:27:15 +01:00
|
|
|
LR = 0;
|
2012-11-15 00:39:56 +01:00
|
|
|
CTR = PC;
|
|
|
|
|
CR.CR = 0x22000082;
|
2013-06-30 10:46:29 +02:00
|
|
|
VSCR.NJ = 1;
|
2013-08-19 01:06:11 +02:00
|
|
|
TB = 0;
|
2015-08-10 21:39:52 +02:00
|
|
|
|
|
|
|
|
//m_state |= CPU_STATE_INTR;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-19 13:36:32 +02:00
|
|
|
void PPUThread::init_stack()
|
2015-02-01 14:52:34 +01:00
|
|
|
{
|
2015-07-01 00:25:52 +02:00
|
|
|
if (!stack_addr)
|
2015-02-01 14:52:34 +01:00
|
|
|
{
|
2015-07-01 00:25:52 +02:00
|
|
|
if (!stack_size)
|
|
|
|
|
{
|
|
|
|
|
throw EXCEPTION("Invalid stack size");
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-11 22:44:53 +02:00
|
|
|
stack_addr = vm::alloc(stack_size, vm::stack);
|
2015-07-01 00:25:52 +02:00
|
|
|
|
|
|
|
|
if (!stack_addr)
|
|
|
|
|
{
|
|
|
|
|
throw EXCEPTION("Out of stack memory");
|
|
|
|
|
}
|
2015-02-01 14:52:34 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-19 13:36:32 +02:00
|
|
|
void PPUThread::close_stack()
|
2015-02-01 14:52:34 +01:00
|
|
|
{
|
2015-07-01 00:25:52 +02:00
|
|
|
if (stack_addr)
|
2015-02-01 14:52:34 +01:00
|
|
|
{
|
2015-08-19 13:04:58 +02:00
|
|
|
vm::dealloc_verbose_nothrow(stack_addr, vm::stack);
|
2015-07-01 00:25:52 +02:00
|
|
|
stack_addr = 0;
|
2015-02-01 14:52:34 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-10 21:39:52 +02:00
|
|
|
bool PPUThread::handle_interrupt()
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-19 13:36:32 +02:00
|
|
|
void PPUThread::do_run()
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-07-01 00:25:52 +02:00
|
|
|
m_dec.reset();
|
2015-03-16 19:44:49 +01:00
|
|
|
|
2015-10-24 20:48:07 +02:00
|
|
|
switch (auto mode = rpcs3::state.config.core.ppu_decoder.value())
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-10-24 20:48:07 +02:00
|
|
|
case ppu_decoder_type::interpreter: // original interpreter
|
2014-04-23 13:59:14 +02:00
|
|
|
{
|
2015-07-01 00:25:52 +02:00
|
|
|
m_dec.reset(new PPUDecoder(new PPUInterpreter(*this)));
|
2015-03-16 19:44:49 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-24 20:48:07 +02:00
|
|
|
case ppu_decoder_type::interpreter2: // alternative interpreter
|
2015-03-16 19:44:49 +01:00
|
|
|
{
|
|
|
|
|
break;
|
2014-04-23 13:59:14 +02:00
|
|
|
}
|
|
|
|
|
|
2015-10-24 20:48:07 +02:00
|
|
|
case ppu_decoder_type::recompiler_llvm:
|
2015-07-01 00:25:52 +02:00
|
|
|
{
|
2014-11-04 17:45:25 +01:00
|
|
|
#ifdef PPU_LLVM_RECOMPILER
|
2015-07-21 17:11:13 +02:00
|
|
|
m_dec.reset(new ppu_recompiler_llvm::CPUHybridDecoderRecompiler(*this));
|
2014-11-04 17:45:25 +01:00
|
|
|
#else
|
|
|
|
|
LOG_ERROR(PPU, "This image does not include PPU JIT (LLVM)");
|
|
|
|
|
Emu.Pause();
|
|
|
|
|
#endif
|
2015-07-01 00:25:52 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2014-08-31 13:10:33 +02:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
//case 3: m_dec.reset(new PPURecompiler(*this)); break;
|
2014-11-19 15:16:30 +01:00
|
|
|
|
2014-04-23 13:59:14 +02:00
|
|
|
default:
|
2015-03-20 17:53:54 +01:00
|
|
|
{
|
|
|
|
|
LOG_ERROR(PPU, "Invalid CPU decoder mode: %d", mode);
|
2014-04-23 13:59:14 +02:00
|
|
|
Emu.Pause();
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
2015-03-20 17:53:54 +01:00
|
|
|
}
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
bool FPRdouble::IsINF(PPCdouble d)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2013-08-17 00:22:26 +02:00
|
|
|
return ((u64&)d & 0x7FFFFFFFFFFFFFFFULL) == 0x7FF0000000000000ULL;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
bool FPRdouble::IsNaN(PPCdouble d)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-07-12 23:06:43 +02:00
|
|
|
return std::isnan((double)d) ? 1 : 0;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
bool FPRdouble::IsQNaN(PPCdouble d)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2013-08-17 00:22:26 +02:00
|
|
|
return
|
|
|
|
|
((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL &&
|
|
|
|
|
((u64&)d & 0x0007FFFFFFFFFFFULL) == 0ULL &&
|
|
|
|
|
((u64&)d & 0x000800000000000ULL) != 0ULL;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
bool FPRdouble::IsSNaN(PPCdouble d)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2013-08-17 00:22:26 +02:00
|
|
|
return
|
|
|
|
|
((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL &&
|
|
|
|
|
((u64&)d & 0x000FFFFFFFFFFFFFULL) != 0ULL &&
|
|
|
|
|
((u64&)d & 0x0008000000000000ULL) == 0ULL;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
int FPRdouble::Cmp(PPCdouble a, PPCdouble b)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
|
|
|
|
if(a < b) return CR_LT;
|
|
|
|
|
if(a > b) return CR_GT;
|
|
|
|
|
if(a == b) return CR_EQ;
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
return CR_SO;
|
2014-04-10 00:54:32 +02:00
|
|
|
}
|
2014-08-15 14:50:59 +02:00
|
|
|
|
2015-07-19 13:36:32 +02:00
|
|
|
u64 PPUThread::get_stack_arg(s32 i)
|
2014-08-23 16:51:51 +02:00
|
|
|
{
|
2015-09-14 18:32:35 +02:00
|
|
|
return vm::ps3::read64(VM_CAST(GPR[1] + 0x70 + 0x8 * (i - 9)));
|
2014-08-23 16:51:51 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-19 13:36:32 +02:00
|
|
|
void PPUThread::fast_call(u32 addr, u32 rtoc)
|
2014-08-19 20:17:20 +02:00
|
|
|
{
|
2015-07-01 00:25:52 +02:00
|
|
|
if (!is_current())
|
|
|
|
|
{
|
|
|
|
|
throw EXCEPTION("Called from the wrong thread");
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-19 20:17:20 +02:00
|
|
|
auto old_PC = PC;
|
2015-04-18 02:25:26 +02:00
|
|
|
auto old_stack = GPR[1];
|
2014-08-19 20:17:20 +02:00
|
|
|
auto old_rtoc = GPR[2];
|
2014-08-20 16:23:48 +02:00
|
|
|
auto old_LR = LR;
|
2015-07-19 13:36:32 +02:00
|
|
|
auto old_task = std::move(custom_task);
|
|
|
|
|
|
|
|
|
|
assert(!old_task || !custom_task);
|
2014-08-19 20:17:20 +02:00
|
|
|
|
|
|
|
|
PC = addr;
|
|
|
|
|
GPR[2] = rtoc;
|
2014-11-30 23:04:47 +01:00
|
|
|
LR = Emu.GetCPUThreadStop();
|
2015-07-19 13:36:32 +02:00
|
|
|
custom_task = nullptr;
|
2014-08-19 20:17:20 +02:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
try
|
|
|
|
|
{
|
2015-11-26 09:06:29 +01:00
|
|
|
cpu_task();
|
2015-07-01 00:25:52 +02:00
|
|
|
}
|
|
|
|
|
catch (CPUThreadReturn)
|
|
|
|
|
{
|
|
|
|
|
}
|
2014-08-19 20:17:20 +02:00
|
|
|
|
2015-07-01 19:09:26 +02:00
|
|
|
m_state &= ~CPU_STATE_RETURN;
|
|
|
|
|
|
2014-08-20 16:23:48 +02:00
|
|
|
PC = old_PC;
|
2015-04-18 03:35:58 +02:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
if (GPR[1] != old_stack) // GPR[1] shouldn't change
|
2015-04-18 03:35:58 +02:00
|
|
|
{
|
2015-07-01 00:25:52 +02:00
|
|
|
throw EXCEPTION("Stack inconsistency (addr=0x%x, rtoc=0x%x, SP=0x%llx, old=0x%llx)", addr, rtoc, GPR[1], old_stack);
|
2015-04-18 03:35:58 +02:00
|
|
|
}
|
|
|
|
|
|
2014-08-19 20:17:20 +02:00
|
|
|
GPR[2] = old_rtoc;
|
|
|
|
|
LR = old_LR;
|
2015-07-19 13:36:32 +02:00
|
|
|
custom_task = std::move(old_task);
|
2014-08-19 20:17:20 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-19 13:36:32 +02:00
|
|
|
void PPUThread::fast_stop()
|
2014-08-15 14:50:59 +02:00
|
|
|
{
|
2015-07-01 19:09:26 +02:00
|
|
|
m_state |= CPU_STATE_RETURN;
|
2014-09-24 20:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
void PPUThread::cpu_task()
|
2014-09-24 20:44:26 +02:00
|
|
|
{
|
2015-03-17 21:03:24 +01:00
|
|
|
SetHostRoundingMode(FPSCR_RN_NEAR);
|
|
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
if (custom_task)
|
2014-09-24 20:44:26 +02:00
|
|
|
{
|
2015-07-19 13:36:32 +02:00
|
|
|
if (check_status()) return;
|
2015-07-01 00:25:52 +02:00
|
|
|
|
2015-03-16 22:38:21 +01:00
|
|
|
return custom_task(*this);
|
2014-09-24 20:44:26 +02:00
|
|
|
}
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2015-08-21 13:07:31 +02:00
|
|
|
if (!g_tls_ppu_decoder_cache)
|
2015-08-10 21:39:52 +02:00
|
|
|
{
|
2015-08-21 13:07:31 +02:00
|
|
|
const auto decoder_cache = fxm::get<ppu_decoder_cache_t>();
|
|
|
|
|
|
|
|
|
|
if (!decoder_cache)
|
|
|
|
|
{
|
|
|
|
|
throw EXCEPTION("PPU Decoder Cache not initialized");
|
|
|
|
|
}
|
2015-08-10 21:39:52 +02:00
|
|
|
|
2015-08-21 13:07:31 +02:00
|
|
|
g_tls_ppu_decoder_cache = decoder_cache.get(); // unsafe (TODO)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto exec_map = g_tls_ppu_decoder_cache->pointer;
|
2015-08-10 21:39:52 +02:00
|
|
|
|
2015-03-16 22:38:21 +01:00
|
|
|
if (m_dec)
|
2014-09-24 20:44:26 +02:00
|
|
|
{
|
2015-07-01 00:25:52 +02:00
|
|
|
while (true)
|
|
|
|
|
{
|
2015-09-18 00:41:14 +02:00
|
|
|
if (m_state && check_status()) break;
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
// decode instruction using specified decoder
|
|
|
|
|
m_dec->DecodeMemory(PC);
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
// next instruction
|
|
|
|
|
PC += 4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2015-08-10 21:39:52 +02:00
|
|
|
// get cached interpreter function address
|
|
|
|
|
const auto func = exec_map[PC / 4];
|
2015-03-21 00:36:05 +01:00
|
|
|
|
2015-08-10 21:39:52 +02:00
|
|
|
// check status
|
2015-09-18 00:41:14 +02:00
|
|
|
if (!m_state)
|
2015-08-10 21:39:52 +02:00
|
|
|
{
|
|
|
|
|
// call interpreter function
|
2015-09-14 18:32:35 +02:00
|
|
|
func(*this, { vm::ps3::read32(PC) });
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2015-08-10 21:39:52 +02:00
|
|
|
// next instruction
|
|
|
|
|
PC += 4;
|
2015-03-16 19:44:49 +01:00
|
|
|
|
2015-08-10 21:39:52 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (check_status())
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-07-01 00:25:52 +02:00
|
|
|
}
|
2015-03-16 19:44:49 +01:00
|
|
|
}
|
2014-09-24 20:44:26 +02:00
|
|
|
}
|
2014-11-19 15:16:30 +01:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
ppu_thread::ppu_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio)
|
2014-11-19 15:16:30 +01:00
|
|
|
{
|
2015-08-05 17:30:32 +02:00
|
|
|
auto ppu = idm::make_ptr<PPUThread>(name);
|
2015-07-01 00:25:52 +02:00
|
|
|
|
|
|
|
|
if (entry)
|
|
|
|
|
{
|
2015-09-14 18:32:35 +02:00
|
|
|
ppu->PC = vm::ps3::read32(entry);
|
|
|
|
|
ppu->GPR[2] = vm::ps3::read32(entry + 4); // rtoc
|
2015-07-01 00:25:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ppu->stack_size = stack_size ? stack_size : Emu.GetPrimaryStackSize();
|
|
|
|
|
ppu->prio = prio ? prio : Emu.GetPrimaryPrio();
|
2014-11-19 15:16:30 +01:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
thread = std::move(ppu);
|
2014-11-19 15:16:30 +01:00
|
|
|
|
|
|
|
|
argc = 0;
|
2014-11-20 20:41:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu_thread& ppu_thread::args(std::initializer_list<std::string> values)
|
|
|
|
|
{
|
|
|
|
|
if (!values.size())
|
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
|
|
assert(argc == 0);
|
|
|
|
|
|
2016-01-14 16:03:08 +01:00
|
|
|
envp.set(vm::alloc(align(SIZE_32(*envp), stack_align), vm::main));
|
2014-11-20 20:41:04 +01:00
|
|
|
*envp = 0;
|
2016-01-14 16:03:08 +01:00
|
|
|
argv.set(vm::alloc(SIZE_32(*argv) * (u32)values.size(), vm::main));
|
2014-11-20 20:41:04 +01:00
|
|
|
|
|
|
|
|
for (auto &arg : values)
|
|
|
|
|
{
|
2015-06-19 17:49:38 +02:00
|
|
|
const u32 arg_size = align(u32(arg.size() + 1), stack_align);
|
|
|
|
|
const u32 arg_addr = vm::alloc(arg_size, vm::main);
|
2014-11-20 20:41:04 +01:00
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
std::memcpy(vm::base(arg_addr), arg.c_str(), arg.size() + 1);
|
2014-11-20 20:41:04 +01:00
|
|
|
|
|
|
|
|
argv[argc++] = arg_addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu_thread& ppu_thread::run()
|
|
|
|
|
{
|
2015-07-19 13:36:32 +02:00
|
|
|
thread->run();
|
2014-11-20 20:41:04 +01:00
|
|
|
|
|
|
|
|
gpr(3, argc);
|
|
|
|
|
gpr(4, argv.addr());
|
|
|
|
|
gpr(5, envp.addr());
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ppu_thread& ppu_thread::gpr(uint index, u64 value)
|
|
|
|
|
{
|
|
|
|
|
assert(index < 32);
|
|
|
|
|
|
2015-03-04 22:51:14 +01:00
|
|
|
static_cast<PPUThread&>(*thread).GPR[index] = value;
|
2014-11-20 20:41:04 +01:00
|
|
|
|
|
|
|
|
return *this;
|
2014-11-29 18:41:18 +01:00
|
|
|
}
|