This commit is contained in:
Oil 2014-12-01 20:47:48 +04:00
commit b736b8616b
54 changed files with 1078 additions and 341 deletions

View file

@ -57,7 +57,7 @@ int fmt::CmpNoCase(const std::string& a, const std::string& b)
return std::equal(a.begin(), return std::equal(a.begin(),
a.end(), a.end(),
b.begin(), b.begin(),
[](const char& a, const char& b){return tolower(a) == tolower(b); }) [](const char& a, const char& b){return ::tolower(a) == ::tolower(b); })
? 0 : -1; ? 0 : -1;
} }
} }
@ -134,3 +134,34 @@ std::vector<std::string> fmt::split(const std::string& source, std::initializer_
return std::move(result); return std::move(result);
} }
std::string fmt::merge(std::vector<std::string> source, const std::string& separator)
{
std::string result;
for (auto &s : source)
{
result += s + separator;
}
return result;
}
std::string fmt::merge(std::initializer_list<std::vector<std::string>> sources, const std::string& separator)
{
std::string result;
for (auto &v : sources)
{
result += fmt::merge(v, separator);
}
return result;
}
std::string fmt::tolower(std::string source)
{
std::transform(source.begin(), source.end(), source.begin(), ::tolower);
return source;
}

View file

@ -194,4 +194,7 @@ namespace fmt{
std::vector<std::string> rSplit(const std::string& source, const std::string& delim); std::vector<std::string> rSplit(const std::string& source, const std::string& delim);
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true); std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true);
std::string merge(std::vector<std::string> source, const std::string& separator);
std::string merge(std::initializer_list<std::vector<std::string>> sources, const std::string& separator);
std::string tolower(std::string source);
} }

View file

@ -90,6 +90,46 @@ void ARMv7Interpreter::ADD_IMM(const u32 data, const ARMv7_encoding type)
imm32 = (data & 0x1c0) >> 6; imm32 = (data & 0x1c0) >> 6;
break; break;
} }
case T2:
{
d = n = (data & 0x700) >> 8;
imm32 = (data & 0xff);
break;
}
case T3:
{
d = (data & 0xf00) >> 8;
n = (data & 0xf0000) >> 16;
set_flags = (data & 0x100000);
imm32 = ThumbExpandImm((data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff));
if (d == 15 && set_flags)
{
throw "CMN (immediate)";
}
if (n == 13)
{
throw "ADD (SP plus immediate)";
}
break;
}
case T4:
{
d = (data & 0xf00) >> 8;
n = (data & 0xf0000) >> 16;
set_flags = false;
imm32 = (data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff);
if (n == 15)
{
throw "ADR";
}
if (n == 13)
{
throw "ADD (SP plus immediate)";
}
break;
}
case A1: throw __FUNCTION__; case A1: throw __FUNCTION__;
default: throw __FUNCTION__; default: throw __FUNCTION__;
} }
@ -115,11 +155,75 @@ void ARMv7Interpreter::ADD_IMM(const u32 data, const ARMv7_encoding type)
void ARMv7Interpreter::ADD_REG(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::ADD_REG(const u32 data, const ARMv7_encoding type)
{ {
bool set_flags = !CPU.ITSTATE;
u32 cond = CPU.ITSTATE.advance();
u32 d = 0;
u32 n = 0;
u32 m = 0;
auto shift_t = SRType_LSL;
u32 shift_n = 0;
switch (type) switch (type)
{ {
case T1:
{
d = (data & 0x7);
n = (data & 0x38) >> 3;
m = (data & 0x1c0) >> 6;
break;
}
case T2:
{
n = d = (data & 0x80) >> 4 | (data & 0x7);
m = (data & 0x78) >> 3;
set_flags = false;
if (n == 13 || m == 13)
{
throw "ADD (SP plus register)";
}
break;
}
case T3:
{
d = (data & 0xf00) >> 8;
n = (data & 0xf0000) >> 16;
m = (data & 0xf);
set_flags = (data & 0x100000);
shift_t = DecodeImmShift((data & 0x30) >> 4, (data & 0x7000) >> 10 | (data & 0xc0) >> 6, &shift_n);
if (d == 15 && set_flags)
{
throw "CMN (register)";
}
if (n == 13)
{
throw "ADD (SP plus register)";
}
break;
}
case A1: throw __FUNCTION__; case A1: throw __FUNCTION__;
default: throw __FUNCTION__; default: throw __FUNCTION__;
} }
if (ConditionPassed(cond))
{
const u32 shifted = Shift(CPU.read_gpr(m), shift_t, shift_n, true);
if (set_flags)
{
bool carry, overflow;
const u32 res = AddWithCarry(CPU.read_gpr(n), shifted, false, carry, overflow);
CPU.write_gpr(d, res);
CPU.APSR.N = res >> 31;
CPU.APSR.Z = res == 0;
CPU.APSR.C = carry;
CPU.APSR.V = overflow;
}
else
{
CPU.write_gpr(d, CPU.read_gpr(n) + shifted);
}
}
} }
void ARMv7Interpreter::ADD_RSR(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::ADD_RSR(const u32 data, const ARMv7_encoding type)
@ -133,20 +237,122 @@ void ARMv7Interpreter::ADD_RSR(const u32 data, const ARMv7_encoding type)
void ARMv7Interpreter::ADD_SPI(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::ADD_SPI(const u32 data, const ARMv7_encoding type)
{ {
u32 cond = CPU.ITSTATE.advance();
u32 d = 13;
bool set_flags = false;
u32 imm32 = 0;
switch (type) switch (type)
{ {
case T1:
{
d = (data & 0x700) >> 8;
imm32 = (data & 0xff) << 2;
break;
}
case T2:
{
imm32 = (data & 0x7f) << 2;
break;
}
case T3:
{
d = (data & 0xf00) >> 8;
set_flags = (data & 0x100000);
imm32 = ThumbExpandImm((data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff));
if (d == 15 && set_flags)
{
throw "CMN (immediate)";
}
break;
}
case T4:
{
d = (data & 0xf00) >> 8;
set_flags = false;
imm32 = (data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff);
break;
}
case A1: throw __FUNCTION__; case A1: throw __FUNCTION__;
default: throw __FUNCTION__; default: throw __FUNCTION__;
} }
if (ConditionPassed(cond))
{
if (set_flags)
{
bool carry, overflow;
const u32 res = AddWithCarry(CPU.SP, imm32, false, carry, overflow);
CPU.write_gpr(d, res);
CPU.APSR.N = res >> 31;
CPU.APSR.Z = res == 0;
CPU.APSR.C = carry;
CPU.APSR.V = overflow;
}
else
{
CPU.write_gpr(d, CPU.SP + imm32);
}
}
} }
void ARMv7Interpreter::ADD_SPR(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::ADD_SPR(const u32 data, const ARMv7_encoding type)
{ {
u32 cond = CPU.ITSTATE.advance();
u32 d = 13;
u32 m = 0;
bool set_flags = false;
auto shift_t = SRType_LSL;
u32 shift_n = 0;
switch (type) switch (type)
{ {
case T1:
{
m = d = (data & 0x80) >> 4 | (data & 0x7);
break;
}
case T2:
{
m = (data & 0x78) >> 3;
if (m == 13)
{
throw "ADD_SPR_T2: T1";
}
break;
}
case T3:
{
d = (data & 0xf00) >> 8;
m = (data & 0xf);
set_flags = (data & 0x100000);
shift_t = DecodeImmShift((data & 0x30) >> 4, (data & 0x7000) >> 10 | (data & 0xc0) >> 6, &shift_n);
break;
}
case A1: throw __FUNCTION__; case A1: throw __FUNCTION__;
default: throw __FUNCTION__; default: throw __FUNCTION__;
} }
if (ConditionPassed(cond))
{
const u32 shifted = Shift(CPU.read_gpr(m), shift_t, shift_n, CPU.APSR.C);
if (set_flags)
{
bool carry, overflow;
const u32 res = AddWithCarry(CPU.SP, shifted, false, carry, overflow);
CPU.write_gpr(d, res);
CPU.APSR.N = res >> 31;
CPU.APSR.Z = res == 0;
CPU.APSR.C = carry;
CPU.APSR.V = overflow;
}
else
{
CPU.write_gpr(d, CPU.SP + CPU.read_gpr(m));
}
}
} }
@ -918,20 +1124,97 @@ void ARMv7Interpreter::LDRSH_REG(const u32 data, const ARMv7_encoding type)
void ARMv7Interpreter::LSL_IMM(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::LSL_IMM(const u32 data, const ARMv7_encoding type)
{ {
bool set_flags = !CPU.ITSTATE;
u32 cond = CPU.ITSTATE.advance();
u32 d = 0;
u32 m = 0;
u32 shift_n = 0;
switch (type) switch (type)
{ {
case T1:
{
d = (data & 0x7);
m = (data & 0x38) >> 3;
shift_n = (data & 0x7c0) >> 6;
if (!shift_n)
{
throw "MOV (register)";
}
break;
}
case T2:
{
d = (data & 0xf00) >> 8;
m = (data & 0xf);
set_flags = (data & 0x100000);
shift_n = (data & 0x7000) >> 10 | (data & 0xc0) >> 6;
if (!shift_n)
{
throw "MOV (register)";
}
break;
}
case A1: throw __FUNCTION__; case A1: throw __FUNCTION__;
default: throw __FUNCTION__; default: throw __FUNCTION__;
} }
if (ConditionPassed(cond))
{
bool carry;
const u32 res = Shift_C(CPU.read_gpr(m), SRType_LSL, shift_n, CPU.APSR.C, carry);
CPU.write_gpr(d, res);
if (set_flags)
{
CPU.APSR.N = res >> 31;
CPU.APSR.Z = res == 0;
CPU.APSR.C = carry;
}
}
} }
void ARMv7Interpreter::LSL_REG(const u32 data, const ARMv7_encoding type) void ARMv7Interpreter::LSL_REG(const u32 data, const ARMv7_encoding type)
{ {
bool set_flags = !CPU.ITSTATE;
u32 cond = CPU.ITSTATE.advance();
u32 d = 0;
u32 n = 0;
u32 m = 0;
switch (type) switch (type)
{ {
case T1:
{
d = n = (data & 0x7);
m = (data & 0x38) >> 3;
break;
}
case T2:
{
d = (data & 0xf00) >> 8;
n = (data & 0xf0000) >> 16;
m = (data & 0xf);
set_flags = (data & 0x100000);
break;
}
case A1: throw __FUNCTION__; case A1: throw __FUNCTION__;
default: throw __FUNCTION__; default: throw __FUNCTION__;
} }
if (ConditionPassed(cond))
{
bool carry;
const u32 res = Shift_C(CPU.read_gpr(n), SRType_LSL, (CPU.read_gpr(m) & 0xff), CPU.APSR.C, carry);
CPU.write_gpr(d, res);
if (set_flags)
{
CPU.APSR.N = res >> 31;
CPU.APSR.Z = res == 0;
CPU.APSR.C = carry;
}
}
} }

View file

@ -132,75 +132,72 @@ public:
return shift_t; return shift_t;
} }
u32 LSL_C(u32 x, int shift, bool& carry_out) u32 LSL_C(u32 x, s32 shift, bool& carry_out)
{ {
u32 extended_x = x << shift; assert(shift > 0);
carry_out = (extended_x >> 31) ? 1 : 0; carry_out = shift <= 32 ? x & (1 << (32 - shift)) : false;
return extended_x & ~(1 << 31); return shift < 32 ? x << shift : 0;
} }
u32 LSL(u32 x, int shift) u32 LSL(u32 x, s32 shift)
{ {
if(!shift) return x; assert(shift >= 0);
bool carry_out; return shift < 32 ? x << shift : 0;
return LSL_C(x, shift, carry_out);
} }
u32 LSR_C(u32 x, int shift, bool& carry_out) u32 LSR_C(u32 x, s32 shift, bool& carry_out)
{ {
carry_out = (x >> (shift - 1)) & 0x1; assert(shift > 0);
return x >> shift; carry_out = shift <= 32 ? x & (1 << (shift - 1)) : false;
return shift < 32 ? x >> shift : 0;
} }
u32 LSR(u32 x, int shift) u32 LSR(u32 x, s32 shift)
{ {
if(!shift) return x; assert(shift >= 0);
bool carry_out; return shift < 32 ? x >> shift : 0;
return LSR_C(x, shift, carry_out);
} }
s32 ASR_C(s32 x, int shift, bool& carry_out) s32 ASR_C(s32 x, s32 shift, bool& carry_out)
{ {
carry_out = (x >> (shift - 1)) & 0x1; assert(shift > 0);
return x >> shift; carry_out = shift <= 32 ? x & (1 << (shift - 1)) : false;
return shift < 32 ? x >> shift : x >> 31;
} }
s32 ASR(s32 x, int shift) s32 ASR(s32 x, s32 shift)
{ {
if(!shift) return x; assert(shift >= 0);
bool carry_out; return shift < 32 ? x >> shift : x >> 31;
return ASR_C(x, shift, carry_out);
} }
u32 ROR_C(u32 x, int shift, bool& carry_out) u32 ROR_C(u32 x, s32 shift, bool& carry_out)
{ {
u32 result = LSR(x, shift) | LSL(x, 32 - shift); assert(shift);
carry_out = (result >> 30) & 0x1; carry_out = x & (1 << (shift - 1));
return result; return x >> shift | x << (32 - shift);
} }
s32 ROR(s32 x, int shift) u32 ROR(u32 x, s32 shift)
{ {
if(!shift) return x; return x >> shift | x << (32 - shift);
bool carry_out;
return ROR_C(x, shift, carry_out);
} }
template<typename T> T RRX_C(T x, bool carry_in, bool& carry_out) u32 RRX_C(u32 x, bool carry_in, bool& carry_out)
{ {
carry_out = x & 0x1; carry_out = x & 0x1;
return ((u32)carry_in << 31) | (x & 0x7ffffffe); return ((u32)carry_in << 31) | (x >> 1);
} }
s32 RRX(s32 x, int shift) u32 RRX(u32 x, bool carry_in)
{ {
if(!shift) return x; return ((u32)carry_in << 31) | (x >> 1);
bool carry_out;
return RRX_C(x, shift, carry_out);
} }
template<typename T> T Shift_C(T value, SRType type, uint amount, bool carry_in, bool& carry_out) template<typename T> T Shift_C(T value, SRType type, s32 amount, bool carry_in, bool& carry_out)
{ {
assert(type != SRType_RRX || amount == 1);
if(amount) if(amount)
{ {
switch(type) switch(type)
@ -209,7 +206,7 @@ public:
case SRType_LSR: return LSR_C(value, amount, carry_out); case SRType_LSR: return LSR_C(value, amount, carry_out);
case SRType_ASR: return ASR_C(value, amount, carry_out); case SRType_ASR: return ASR_C(value, amount, carry_out);
case SRType_ROR: return ROR_C(value, amount, carry_out); case SRType_ROR: return ROR_C(value, amount, carry_out);
case SRType_RRX: return RRX_C(value, amount, carry_out); case SRType_RRX: return RRX_C(value, carry_in, carry_out);
} }
} }
@ -217,7 +214,7 @@ public:
return value; return value;
} }
template<typename T> T Shift(T value, SRType type, u32 amount, bool carry_in) template<typename T> T Shift(T value, SRType type, s32 amount, bool carry_in)
{ {
bool carry_out; bool carry_out;
return Shift_C(value, type, amount, carry_in, carry_out); return Shift_C(value, type, amount, carry_in, carry_out);

View file

@ -350,6 +350,15 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] =
ARMv7_OP4(0x0fe0, 0x0010, 0x00a0, 0x0000, A1, ADC_REG), ARMv7_OP4(0x0fe0, 0x0010, 0x00a0, 0x0000, A1, ADC_REG),
ARMv7_OP4(0x0fe0, 0x0090, 0x00a0, 0x0010, A1, ADC_RSR), ARMv7_OP4(0x0fe0, 0x0090, 0x00a0, 0x0010, A1, ADC_RSR),
ARMv7_OP2(0xf800, 0xa800, T1, ADD_SPI),
ARMv7_OP2(0xff80, 0xb000, T2, ADD_SPI),
ARMv7_OP4(0xfbef, 0x8000, 0xf10d, 0x0000, T3, ADD_SPI),
ARMv7_OP4(0xfbff, 0x8000, 0xf20d, 0x0000, T4, ADD_SPI),
ARMv7_OP4(0x0fef, 0x0000, 0x028d, 0x0000, A1, ADD_SPI),
ARMv7_OP2(0xff78, 0x4468, T1, ADD_SPR),
ARMv7_OP2(0xff87, 0x4485, T2, ADD_SPR),
ARMv7_OP4(0xffef, 0x8000, 0xeb0d, 0x0000, T3, ADD_SPR),
ARMv7_OP4(0x0fef, 0x0010, 0x008d, 0x0000, A1, ADD_SPR),
ARMv7_OP2(0xfe00, 0x1c00, T1, ADD_IMM), ARMv7_OP2(0xfe00, 0x1c00, T1, ADD_IMM),
ARMv7_OP2(0xf800, 0x3000, T2, ADD_IMM), ARMv7_OP2(0xf800, 0x3000, T2, ADD_IMM),
ARMv7_OP4(0xfbe0, 0x8000, 0xf100, 0x0000, T3, ADD_IMM), ARMv7_OP4(0xfbe0, 0x8000, 0xf100, 0x0000, T3, ADD_IMM),
@ -360,15 +369,6 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] =
ARMv7_OP4(0xffe0, 0x8000, 0xeb00, 0x0000, T3, ADD_REG), ARMv7_OP4(0xffe0, 0x8000, 0xeb00, 0x0000, T3, ADD_REG),
ARMv7_OP4(0x0fe0, 0x0010, 0x0080, 0x0000, A1, ADD_REG), ARMv7_OP4(0x0fe0, 0x0010, 0x0080, 0x0000, A1, ADD_REG),
ARMv7_OP4(0x0fe0, 0x0090, 0x0080, 0x0010, A1, ADD_RSR), ARMv7_OP4(0x0fe0, 0x0090, 0x0080, 0x0010, A1, ADD_RSR),
ARMv7_OP2(0xf800, 0xa800, T1, ADD_SPI),
ARMv7_OP2(0xff80, 0xb000, T2, ADD_SPI),
ARMv7_OP4(0xfbef, 0x8000, 0xf10d, 0x0000, T3, ADD_SPI),
ARMv7_OP4(0xfbff, 0x8000, 0xf20d, 0x0000, T4, ADD_SPI),
ARMv7_OP4(0x0fef, 0x0000, 0x028d, 0x0000, A1, ADD_SPI),
ARMv7_OP2(0xff78, 0x4468, T1, ADD_SPR),
ARMv7_OP2(0xff87, 0x4485, T2, ADD_SPR),
ARMv7_OP4(0xffef, 0x8000, 0xeb0d, 0x0000, T3, ADD_SPR),
ARMv7_OP4(0x0fef, 0x0010, 0x008d, 0x0000, A1, ADD_SPR),
ARMv7_OP2(0xf800, 0xa000, T1, ADR), ARMv7_OP2(0xf800, 0xa000, T1, ADR),
ARMv7_OP4(0xfbff, 0x8000, 0xf2af, 0x0000, T2, ADR), ARMv7_OP4(0xfbff, 0x8000, 0xf2af, 0x0000, T2, ADR),

View file

@ -102,6 +102,33 @@ void ARMv7Thread::DoCode()
{ {
} }
void ARMv7Thread::FastCall(u32 addr)
{
auto old_status = m_status;
auto old_PC = PC;
auto old_stack = SP;
auto old_LR = LR;
auto old_thread = GetCurrentNamedThread();
m_status = Running;
PC = addr;
LR = Emu.GetCPUThreadStop();
SetCurrentNamedThread(this);
CPUThread::Task();
m_status = old_status;
PC = old_PC;
SP = old_stack;
LR = old_LR;
SetCurrentNamedThread(old_thread);
}
void ARMv7Thread::FastStop()
{
m_status = Stopped;
}
arm7_thread::arm7_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio) arm7_thread::arm7_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio)
{ {
thread = &Emu.GetCPU().AddThread(CPU_THREAD_ARMv7); thread = &Emu.GetCPU().AddThread(CPU_THREAD_ARMv7);

View file

@ -123,6 +123,9 @@ public:
virtual void InitRegs(); virtual void InitRegs();
virtual void InitStack(); virtual void InitStack();
u32 GetStackArg(u32 pos); u32 GetStackArg(u32 pos);
void FastCall(u32 addr);
void FastStop();
virtual void DoRun();
public: public:
virtual std::string RegsToString(); virtual std::string RegsToString();
@ -131,7 +134,6 @@ public:
protected: protected:
virtual void DoReset(); virtual void DoReset();
virtual void DoRun();
virtual void DoPause(); virtual void DoPause();
virtual void DoResume(); virtual void DoResume();
virtual void DoStop(); virtual void DoStop();
@ -153,20 +155,20 @@ public:
if (!values.size()) if (!values.size())
return *this; return *this;
assert(argc == 0); //assert(argc == 0);
envp.set(vm::alloc((u32)sizeof(envp), stack_align, vm::main)); //envp.set(vm::alloc((u32)sizeof(envp), stack_align, vm::main));
*envp = 0; //*envp = 0;
argv.set(vm::alloc(u32(sizeof(argv)* values.size()), stack_align, vm::main)); //argv.set(vm::alloc(u32(sizeof(argv)* values.size()), stack_align, vm::main));
for (auto &arg : values) for (auto &arg : values)
{ {
u32 arg_size = align(u32(arg.size() + 1), stack_align); //u32 arg_size = align(u32(arg.size() + 1), stack_align);
u32 arg_addr = vm::alloc(arg_size, stack_align, vm::main); //u32 arg_addr = vm::alloc(arg_size, stack_align, vm::main);
std::strcpy(vm::get_ptr<char>(arg_addr), arg.c_str()); //std::strcpy(vm::get_ptr<char>(arg_addr), arg.c_str());
argv[argc++] = arg_addr; //argv[argc++] = arg_addr;
} }
return *this; return *this;
@ -176,9 +178,9 @@ public:
{ {
thread->Run(); thread->Run();
static_cast<ARMv7Thread*>(thread)->GPR[3] = argc; //static_cast<ARMv7Thread*>(thread)->GPR[0] = argc;
static_cast<ARMv7Thread*>(thread)->GPR[4] = argv.addr(); //static_cast<ARMv7Thread*>(thread)->GPR[1] = argv.addr();
static_cast<ARMv7Thread*>(thread)->GPR[5] = envp.addr(); //static_cast<ARMv7Thread*>(thread)->GPR[2] = envp.addr();
return *this; return *this;
} }

View file

@ -1,18 +1,91 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/CPU/CPUThreadManager.h"
#include "Emu/ARMv7/ARMv7Thread.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/PSVFuncList.h"
extern psv_log_base sceLibKernel; extern psv_log_base sceLibKernel;
#define RETURN_ERROR(code) { Emu.Pause(); sceLibKernel.Error("%s() failed: %s", __FUNCTION__, #code); return code; }
#pragma pack(push, 4)
typedef s32(*SceKernelThreadEntry)(u32 argSize, vm::psv::ptr<void> pArgBlock); typedef s32(*SceKernelThreadEntry)(u32 argSize, vm::psv::ptr<void> pArgBlock);
union SceKernelSysClock
{
struct
{
u32 low;
u32 hi;
};
u64 quad;
};
struct SceKernelThreadOptParam struct SceKernelThreadOptParam
{ {
u32 size; u32 size;
u32 attr; u32 attr;
}; };
struct SceKernelThreadInfo
{
u32 size;
s32 processId;
char name[32];
u32 attr;
u32 status;
SceKernelThreadEntry entry;
vm::psv::ptr<void> pStack;
u32 stackSize;
s32 initPriority;
s32 currentPriority;
s32 initCpuAffinityMask;
s32 currentCpuAffinityMask;
s32 currentCpuId;
s32 lastExecutedCpuId;
u32 waitType;
s32 waitId;
s32 exitStatus;
SceKernelSysClock runClocks;
u32 intrPreemptCount;
u32 threadPreemptCount;
u32 threadReleaseCount;
s32 changeCpuCount;
s32 fNotifyCallback;
s32 reserved;
};
struct SceKernelThreadRunStatus
{
u32 size;
struct
{
s32 processId;
s32 threadId;
s32 priority;
} cpuInfo[4];
};
struct SceKernelSystemInfo
{
u32 size;
u32 activeCpuMask;
struct
{
SceKernelSysClock idleClock;
u32 comesOutOfIdleCount;
u32 threadSwitchCount;
} cpuInfo[4];
};
#pragma pack(pop)
s32 sceKernelCreateThread( s32 sceKernelCreateThread(
vm::psv::ptr<const char> pName, vm::psv::ptr<const char> pName,
vm::psv::ptr<SceKernelThreadEntry> entry, vm::psv::ptr<SceKernelThreadEntry> entry,
@ -22,9 +95,205 @@ s32 sceKernelCreateThread(
s32 cpuAffinityMask, s32 cpuAffinityMask,
vm::psv::ptr<const SceKernelThreadOptParam> pOptParam) vm::psv::ptr<const SceKernelThreadOptParam> pOptParam)
{ {
sceLibKernel.Todo("sceKernelCreateThread(pName_addr=0x%x ('%s'), entry_addr=0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam_addr=0x%x)", sceLibKernel.Error("sceKernelCreateThread(pName_addr=0x%x ('%s'), entry_addr=0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam_addr=0x%x)",
pName.addr(), pName.get_ptr(), entry.addr(), initPriority, stackSize, attr, cpuAffinityMask, pOptParam.addr()); pName.addr(), pName.get_ptr(), entry.addr(), initPriority, stackSize, attr, cpuAffinityMask, pOptParam.addr());
std::string name = pName.get_ptr();
ARMv7Thread& new_thread = *(ARMv7Thread*)&Emu.GetCPU().AddThread(CPU_THREAD_ARMv7);
u32 id = new_thread.GetId();
new_thread.SetEntry(entry.addr() ^ 1);
new_thread.SetPrio(initPriority);
new_thread.SetStackSize(stackSize);
new_thread.SetName(name);
sceLibKernel.Error("*** New ARMv7 Thread [%s] (entry=0x%x): id = %d", name.c_str(), entry, id);
new_thread.Run();
Emu.Pause();
return id;
}
s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr<const void> pArgBlock)
{
sceLibKernel.Error("sceKernelStartThread(threadId=%d, argSize=%d, pArgBlock_addr=0x%x)", threadId, argSize, pArgBlock.addr());
CPUThread* t = Emu.GetCPU().GetThread(threadId);
if (!t || t->GetType() != CPU_THREAD_ARMv7)
{
RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID);
}
// push arg block onto the stack
u32 pos = (static_cast<ARMv7Thread*>(t)->SP -= argSize);
memcpy(vm::get_ptr<void>(pos), pArgBlock.get_ptr(), argSize);
// set SceKernelThreadEntry function arguments
static_cast<ARMv7Thread*>(t)->write_gpr(0, argSize);
static_cast<ARMv7Thread*>(t)->write_gpr(1, pos);
t->Exec();
return SCE_OK;
}
s32 sceKernelExitThread(ARMv7Thread& CPU, s32 exitStatus)
{
sceLibKernel.Error("sceKernelExitThread(exitStatus=0x%x)", exitStatus);
// exit status is stored in r0
CPU.Stop();
return SCE_OK;
}
s32 sceKernelDeleteThread(s32 threadId)
{
sceLibKernel.Todo("sceKernelDeleteThread(threadId=%d)", threadId);
return SCE_OK;
}
s32 sceKernelExitDeleteThread(s32 exitStatus)
{
sceLibKernel.Todo("sceKernelExitDeleteThread(exitStatus=0x%x)", exitStatus);
return SCE_OK;
}
s32 sceKernelChangeThreadCpuAffinityMask(s32 threadId, s32 cpuAffinityMask)
{
sceLibKernel.Todo("sceKernelChangeThreadCpuAffinityMask(threadId=%d, cpuAffinityMask=0x%x)", threadId, cpuAffinityMask);
return SCE_OK;
}
s32 sceKernelGetThreadCpuAffinityMask(s32 threadId)
{
sceLibKernel.Todo("sceKernelGetThreadCpuAffinityMask(threadId=0x%x)", threadId);
return SCE_OK;
}
s32 sceKernelChangeThreadPriority(s32 threadId, s32 priority)
{
sceLibKernel.Todo("sceKernelChangeThreadPriority(threadId=0x%x, priority=%d)", threadId, priority);
return SCE_OK;
}
s32 sceKernelGetThreadCurrentPriority()
{
sceLibKernel.Todo("sceKernelGetThreadCurrentPriority()");
return SCE_OK;
}
s32 sceKernelGetThreadId()
{
sceLibKernel.Todo("sceKernelGetThreadId()");
return SCE_OK;
}
s32 sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr)
{
sceLibKernel.Todo("sceKernelChangeCurrentThreadAttr()");
return SCE_OK;
}
s32 sceKernelGetThreadExitStatus(s32 threadId, vm::psv::ptr<s32> pExitStatus)
{
sceLibKernel.Todo("sceKernelGetThreadExitStatus(threadId=%d, pExitStatus_addr=0x%x)", threadId, pExitStatus.addr());
return SCE_OK;
}
s32 sceKernelGetProcessId()
{
sceLibKernel.Todo("sceKernelGetProcessId()");
return SCE_OK;
}
s32 sceKernelCheckWaitableStatus()
{
sceLibKernel.Todo("sceKernelCheckWaitableStatus()");
return SCE_OK;
}
s32 sceKernelGetThreadInfo(s32 threadId, vm::psv::ptr<SceKernelThreadInfo> pInfo)
{
sceLibKernel.Todo("sceKernelGetThreadInfo(threadId=%d, pInfo_addr=0x%x)", threadId, pInfo.addr());
return SCE_OK;
}
s32 sceKernelGetThreadRunStatus(vm::psv::ptr<SceKernelThreadRunStatus> pStatus)
{
sceLibKernel.Todo("sceKernelGetThreadRunStatus(pStatus_addr=0x%x)", pStatus.addr());
return SCE_OK;
}
s32 sceKernelGetSystemInfo(vm::psv::ptr<SceKernelSystemInfo> pInfo)
{
sceLibKernel.Todo("sceKernelGetSystemInfo(pInfo_addr=0x%x)", pInfo.addr());
return SCE_OK;
}
s32 sceKernelGetThreadmgrUIDClass(s32 uid)
{
sceLibKernel.Todo("sceKernelGetThreadmgrUIDClass(uid=%d)", uid);
return SCE_OK;
}
s32 sceKernelChangeThreadVfpException(s32 clearMask, s32 setMask)
{
sceLibKernel.Todo("sceKernelChangeThreadVfpException(clearMask=0x%x, setMask=0x%x)", clearMask, setMask);
return SCE_OK;
}
s32 sceKernelGetCurrentThreadVfpException()
{
sceLibKernel.Todo("sceKernelGetCurrentThreadVfpException()");
return SCE_OK;
}
s32 sceKernelDelayThread(u32 usec)
{
sceLibKernel.Todo("sceKernelDelayThread()");
return SCE_OK;
}
s32 sceKernelDelayThreadCB(u32 usec)
{
sceLibKernel.Todo("sceKernelDelayThreadCB()");
return SCE_OK;
}
s32 sceKernelWaitThreadEnd(s32 threadId, vm::psv::ptr<s32> pExitStatus, vm::psv::ptr<u32> pTimeout)
{
sceLibKernel.Todo("sceKernelWaitThreadEnd(threadId=%d, pExitStatus_addr=0x%x, pTimeout_addr=0x%x)", threadId, pExitStatus.addr(), pTimeout.addr());
return SCE_OK;
}
s32 sceKernelWaitThreadEndCB(s32 threadId, vm::psv::ptr<s32> pExitStatus, vm::psv::ptr<u32> pTimeout)
{
sceLibKernel.Todo("sceKernelWaitThreadEndCB(threadId=%d, pExitStatus_addr=0x%x, pTimeout_addr=0x%x)", threadId, pExitStatus.addr(), pTimeout.addr());
return SCE_OK; return SCE_OK;
} }
@ -145,8 +414,8 @@ psv_log_base sceLibKernel = []() -> psv_log_base
//REG_FUNC(0x4C7AD128, sceKernelPowerLock); //REG_FUNC(0x4C7AD128, sceKernelPowerLock);
//REG_FUNC(0xAF8E9C11, sceKernelPowerUnlock); //REG_FUNC(0xAF8E9C11, sceKernelPowerUnlock);
//REG_FUNC(0xB295EB61, sceKernelGetTLSAddr); //REG_FUNC(0xB295EB61, sceKernelGetTLSAddr);
//REG_FUNC(0xFB972F9, sceKernelGetThreadId); REG_FUNC(0xFB972F9, sceKernelGetThreadId);
//REG_FUNC(0xA37A6057, sceKernelGetCurrentThreadVfpException); REG_FUNC(0xA37A6057, sceKernelGetCurrentThreadVfpException);
//REG_FUNC(0xCA71EA2, sceKernelSendMsgPipe); //REG_FUNC(0xCA71EA2, sceKernelSendMsgPipe);
//REG_FUNC(0xA5CA74AC, sceKernelSendMsgPipeCB); //REG_FUNC(0xA5CA74AC, sceKernelSendMsgPipeCB);
//REG_FUNC(0xDFC670E0, sceKernelTrySendMsgPipe); //REG_FUNC(0xDFC670E0, sceKernelTrySendMsgPipe);
@ -158,23 +427,23 @@ psv_log_base sceLibKernel = []() -> psv_log_base
//REG_FUNC(0x9EF798C1, sceKernelTryLockLwMutex); //REG_FUNC(0x9EF798C1, sceKernelTryLockLwMutex);
//REG_FUNC(0x499EA781, sceKernelUnlockLwMutex); //REG_FUNC(0x499EA781, sceKernelUnlockLwMutex);
//REG_FUNC(0xF7D8F1FC, sceKernelGetLwMutexInfo); //REG_FUNC(0xF7D8F1FC, sceKernelGetLwMutexInfo);
//REG_FUNC(0xDDB395A9, sceKernelWaitThreadEnd); REG_FUNC(0xDDB395A9, sceKernelWaitThreadEnd);
//REG_FUNC(0xC54941ED, sceKernelWaitThreadEndCB); REG_FUNC(0xC54941ED, sceKernelWaitThreadEndCB);
//REG_FUNC(0xD5DC26C4, sceKernelGetThreadExitStatus); REG_FUNC(0xD5DC26C4, sceKernelGetThreadExitStatus);
//REG_FUNC(0x4373B548, __sce_aeabi_idiv0); //REG_FUNC(0x4373B548, __sce_aeabi_idiv0);
//REG_FUNC(0xFB235848, __sce_aeabi_ldiv0); //REG_FUNC(0xFB235848, __sce_aeabi_ldiv0);
//REG_FUNC(0xF08DE149, sceKernelStartThread); REG_FUNC(0xF08DE149, sceKernelStartThread);
//REG_FUNC(0x58DDAC4F, sceKernelDeleteThread); REG_FUNC(0x58DDAC4F, sceKernelDeleteThread);
//REG_FUNC(0x5150577B, sceKernelChangeThreadCpuAffinityMask); REG_FUNC(0x5150577B, sceKernelChangeThreadCpuAffinityMask);
//REG_FUNC(0x8C57AC2A, sceKernelGetThreadCpuAffinityMask); REG_FUNC(0x8C57AC2A, sceKernelGetThreadCpuAffinityMask);
//REG_FUNC(0xDF7E6EDA, sceKernelChangeThreadPriority); REG_FUNC(0xDF7E6EDA, sceKernelChangeThreadPriority);
//REG_FUNC(0xBCB63B66, sceKernelGetThreadStackFreeSize); //REG_FUNC(0xBCB63B66, sceKernelGetThreadStackFreeSize);
//REG_FUNC(0x8D9C5461, sceKernelGetThreadInfo); REG_FUNC(0x8D9C5461, sceKernelGetThreadInfo);
//REG_FUNC(0xD6B01013, sceKernelGetThreadRunStatus); REG_FUNC(0xD6B01013, sceKernelGetThreadRunStatus);
//REG_FUNC(0xE0241FAA, sceKernelGetSystemInfo); REG_FUNC(0xE0241FAA, sceKernelGetSystemInfo);
//REG_FUNC(0xF994FE65, sceKernelGetThreadmgrUIDClass); REG_FUNC(0xF994FE65, sceKernelGetThreadmgrUIDClass);
//REG_FUNC(0xB4DE10C7, sceKernelGetActiveCpuMask); //REG_FUNC(0xB4DE10C7, sceKernelGetActiveCpuMask);
//REG_FUNC(0x2C1321A3, sceKernelChangeThreadVfpException); REG_FUNC(0x2C1321A3, sceKernelChangeThreadVfpException);
//REG_FUNC(0x3849359A, sceKernelCreateCallback); //REG_FUNC(0x3849359A, sceKernelCreateCallback);
//REG_FUNC(0x88DD1BC8, sceKernelGetCallbackInfo); //REG_FUNC(0x88DD1BC8, sceKernelGetCallbackInfo);
//REG_FUNC(0x464559D3, sceKernelDeleteCallback); //REG_FUNC(0x464559D3, sceKernelDeleteCallback);
@ -380,15 +649,15 @@ psv_log_base sceLibKernel = []() -> psv_log_base
//REG_FUNC(0x800EDCC1, sceKernelClearDipsw); //REG_FUNC(0x800EDCC1, sceKernelClearDipsw);
/* SceThreadmgr */ /* SceThreadmgr */
//REG_FUNC(0xC8A38E1, sceKernelExitThread); REG_FUNC(0xC8A38E1, sceKernelExitThread);
//REG_FUNC(0x1D17DECF, sceKernelExitDeleteThread); REG_FUNC(0x1D17DECF, sceKernelExitDeleteThread);
//REG_FUNC(0x4B675D05, sceKernelDelayThread); REG_FUNC(0x4B675D05, sceKernelDelayThread);
//REG_FUNC(0x9C0180E1, sceKernelDelayThreadCB); REG_FUNC(0x9C0180E1, sceKernelDelayThreadCB);
//REG_FUNC(0x1173F8, sceKernelChangeActiveCpuMask); //REG_FUNC(0x1173F8, sceKernelChangeActiveCpuMask);
//REG_FUNC(0x1414F0B, sceKernelGetThreadCurrentPriority); REG_FUNC(0x1414F0B, sceKernelGetThreadCurrentPriority);
//REG_FUNC(0x751C9B7A, sceKernelChangeCurrentThreadAttr); REG_FUNC(0x751C9B7A, sceKernelChangeCurrentThreadAttr);
//REG_FUNC(0xD9BD74EB, sceKernelCheckWaitableStatus); REG_FUNC(0xD9BD74EB, sceKernelCheckWaitableStatus);
//REG_FUNC(0x9DCB4B7A, sceKernelGetProcessId); REG_FUNC(0x9DCB4B7A, sceKernelGetProcessId);
//REG_FUNC(0xE53E41F6, sceKernelCheckCallback); //REG_FUNC(0xE53E41F6, sceKernelCheckCallback);
//REG_FUNC(0xF4EE4FA9, sceKernelGetSystemTimeWide); //REG_FUNC(0xF4EE4FA9, sceKernelGetSystemTimeWide);
//REG_FUNC(0x47F6DE49, sceKernelGetSystemTimeLow); //REG_FUNC(0x47F6DE49, sceKernelGetSystemTimeLow);

View file

@ -44,9 +44,11 @@ namespace sce_libc_func
::memcpy(dst.get_ptr(), src.get_ptr(), size); ::memcpy(dst.get_ptr(), src.get_ptr(), size);
} }
void _Assert() void _Assert(vm::psv::ptr<const char> text, vm::psv::ptr<const char> func)
{ {
sceLibc.Todo(__FUNCTION__); sceLibc.Error("_Assert(text_addr=0x%x, func_addr=0x%x)", text.addr(), func.addr());
LOG_ERROR(TTY, "%s : %s", func.get_ptr(), text.get_ptr());
Emu.Pause(); Emu.Pause();
} }
} }

View file

@ -2,30 +2,36 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "PSVFuncList.h" #include "PSVFuncList.h"
std::vector<psv_func> g_psv_func_list = []() -> std::vector<psv_func> std::vector<psv_func> g_psv_func_list;
{
std::vector<psv_func> v;
psv_func f =
{
0xdeadbeef,
"INVALID FUNCTION",
new psv_func_detail::func_binder<u32>([]() -> u32
{
LOG_ERROR(HLE, "Unimplemented function found");
Emu.Pause();
return 0xffffffffu;
}),
nullptr,
};
v.push_back(f);
return v;
}();
void add_psv_func(psv_func& data) void add_psv_func(psv_func& data)
{ {
if (!g_psv_func_list.size())
{
psv_func unimplemented;
unimplemented.nid = 0x00000000; // must not be a valid id
unimplemented.name = "INVALID FUNCTION (0x0)";
unimplemented.func.reset(new psv_func_detail::func_binder<u32>([]() -> u32
{
LOG_ERROR(HLE, "Unimplemented function executed");
Emu.Pause();
return 0xffffffffu;
}));
g_psv_func_list.push_back(unimplemented);
psv_func hle_return;
hle_return.nid = 0x00000001; // must not be a valid id
hle_return.name = "INVALID FUNCTION (0x1)";
hle_return.func.reset(new psv_func_detail::func_binder<void, ARMv7Thread&>([](ARMv7Thread& CPU)
{
CPU.FastStop();
return;
}));
g_psv_func_list.push_back(hle_return);
}
g_psv_func_list.push_back(data); g_psv_func_list.push_back(data);
} }

View file

@ -643,10 +643,10 @@ namespace psv_func_detail
struct psv_func struct psv_func
{ {
const u32 nid; u32 nid;
const char* const name; const char* name;
psv_func_caller* const func; std::shared_ptr<psv_func_caller> func;
psv_log_base* const module; psv_log_base* module;
}; };
void add_psv_func(psv_func& data); void add_psv_func(psv_func& data);
@ -654,13 +654,11 @@ void add_psv_func(psv_func& data);
template<typename RT, typename... T> template<typename RT, typename... T>
void reg_psv_func(u32 nid, psv_log_base* module, const char* name, RT(*func)(T...)) void reg_psv_func(u32 nid, psv_log_base* module, const char* name, RT(*func)(T...))
{ {
psv_func f = psv_func f;
{ f.nid = nid;
nid, f.name = name;
name, f.func.reset(new psv_func_detail::func_binder<RT, T...>(func));
new psv_func_detail::func_binder<RT, T...>(func), f.module = module;
module
};
add_psv_func(f); add_psv_func(f);
} }

View file

@ -92,7 +92,7 @@ void PPUThread::InitRegs()
//GPR[12] = Emu.GetMallocPageSize(); //GPR[12] = Emu.GetMallocPageSize();
GPR[13] = Memory.PRXMem.GetStartAddr() + 0x7060; GPR[13] = Memory.PRXMem.GetStartAddr() + 0x7060;
LR = Emu.GetPPUThreadExit(); LR = Emu.GetCPUThreadExit();
CTR = PC; CTR = PC;
CR.CR = 0x22000082; CR.CR = 0x22000082;
VSCR.NJ = 1; VSCR.NJ = 1;
@ -202,7 +202,7 @@ u64 PPUThread::FastCall2(u32 addr, u32 rtoc)
m_status = Running; m_status = Running;
PC = addr; PC = addr;
GPR[2] = rtoc; GPR[2] = rtoc;
LR = Emu.m_ppu_thr_stop; LR = Emu.GetCPUThreadStop();
SetCurrentNamedThread(this); SetCurrentNamedThread(this);
CPUThread::Task(); CPUThread::Task();

View file

@ -1715,13 +1715,10 @@ private:
} }
else else
{ {
// rotate left
const XmmLink& va = XmmGet(ra, rt); const XmmLink& va = XmmGet(ra, rt);
const XmmLink& v1 = XmmCopy(va); c.palignr(va.get(), va.get(), 16 - s);
c.pslldq(va.get(), s);
c.psrldq(v1.get(), 16 - s);
c.por(va.get(), v1.get());
XmmFinalize(va, rt); XmmFinalize(va, rt);
XmmFinalize(v1);
} }
LOG_OPCODE(); LOG_OPCODE();
} }

View file

@ -8,23 +8,9 @@
#undef CreateFile #undef CreateFile
int sort_devices(const void* _a, const void* _b)
{
const vfsDevice& a = **(const vfsDevice**)_a;
const vfsDevice& b = **(const vfsDevice**)_b;
if (a.GetPs3Path().length() > b.GetPs3Path().length()) return 1;
if (a.GetPs3Path().length() < b.GetPs3Path().length()) return -1;
return 0;
}
std::vector<std::string> simplify_path_blocks(const std::string& path) std::vector<std::string> simplify_path_blocks(const std::string& path)
{ {
std::string lower_path = path; std::vector<std::string> path_blocks = std::move(fmt::split(fmt::tolower(path), { "/", "\\" }));
std::transform(lower_path.begin(), lower_path.end(), lower_path.begin(), ::tolower);
std::vector<std::string> path_blocks = std::move(fmt::split(lower_path, { "/", "\\" }));
for (size_t i = 0; i < path_blocks.size(); ++i) for (size_t i = 0; i < path_blocks.size(); ++i)
{ {
@ -53,19 +39,11 @@ std::string simplify_path(const std::string& path, bool is_dir)
if (is_dir) if (is_dir)
{ {
for (auto &dir : path_blocks) result = fmt::merge(path_blocks, "/");
{
result += dir + "/";
}
} }
else else
{ {
for (size_t i = 0; i < path_blocks.size() - 1; ++i) result = fmt::merge(std::vector<std::string>(path_blocks.begin(), path_blocks.end() - 1), "/") + path_blocks[path_blocks.size() - 1];
{
result += path_blocks[i] + "/";
}
result += path_blocks[path_blocks.size() - 1];
} }
return result; return result;
@ -76,12 +54,6 @@ VFS::~VFS()
UnMountAll(); UnMountAll();
} }
std::string VFS::FindEntry(const std::string &path)
{
return path;
return cwd + "/" + path;
}
void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device) void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device)
{ {
std::string simpl_ps3_path = simplify_path(ps3_path, true); std::string simpl_ps3_path = simplify_path(ps3_path, true);
@ -93,10 +65,43 @@ void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsD
if (m_devices.size() > 1) if (m_devices.size() > 1)
{ {
//std::qsort(m_devices.GetPtr(), m_devices.GetCount(), sizeof(vfsDevice*), sort_devices); std::sort(m_devices.begin(), m_devices.end(), [](vfsDevice *a, vfsDevice *b) { return b->GetPs3Path().length() < a->GetPs3Path().length(); });
} }
} }
void VFS::Link(const std::string& mount_point, const std::string& ps3_path)
{
links[simplify_path_blocks(mount_point)] = simplify_path_blocks(ps3_path);
}
std::string VFS::GetLinked(std::string ps3_path) const
{
ps3_path = fmt::tolower(ps3_path);
auto path_blocks = fmt::split(ps3_path, { "/", "\\" });
for (auto link : links)
{
if (path_blocks.size() < link.first.size())
continue;
bool is_ok = true;
for (size_t i = 0; i < link.first.size(); ++i)
{
if (link.first[i] != path_blocks[i])
{
is_ok = false;
break;
}
}
if (is_ok)
return fmt::merge({ link.second, std::vector<std::string>(path_blocks.begin() + link.first.size(), path_blocks.end()) }, "/");
}
return ps3_path;
}
void VFS::UnMount(const std::string& ps3_path) void VFS::UnMount(const std::string& ps3_path)
{ {
std::string simpl_ps3_path = simplify_path(ps3_path, true); std::string simpl_ps3_path = simplify_path(ps3_path, true);
@ -285,8 +290,9 @@ bool VFS::RenameDir(const std::string& ps3_path_from, const std::string& ps3_pat
vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const
{ {
auto try_get_device = [this, &path](const std::vector<std::string>& ps3_path_blocks) -> vfsDevice* auto try_get_device = [this, &path](const std::string& ps3_path) -> vfsDevice*
{ {
std::vector<std::string> ps3_path_blocks = simplify_path_blocks(ps3_path);
size_t max_eq = 0; size_t max_eq = 0;
int max_i = -1; int max_i = -1;
@ -328,10 +334,10 @@ vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const
return m_devices[max_i]; return m_devices[max_i];
}; };
if (auto res = try_get_device(simplify_path_blocks(ps3_path))) if (auto res = try_get_device(GetLinked(ps3_path)))
return res; return res;
if (auto res = try_get_device(simplify_path_blocks(cwd + ps3_path))) if (auto res = try_get_device(GetLinked(cwd + ps3_path)))
return res; return res;
return nullptr; return nullptr;
@ -415,6 +421,8 @@ void VFS::Init(const std::string& path)
fmt::Replace(mpath, "$(GameDir)", cwd); fmt::Replace(mpath, "$(GameDir)", cwd);
Mount(entry.mount, mpath, dev); Mount(entry.mount, mpath, dev);
} }
Link("/app_home/", "/host_root/" + cwd);
} }
void VFS::SaveLoadDevices(std::vector<VFSManagerEntry>& res, bool is_load) void VFS::SaveLoadDevices(std::vector<VFSManagerEntry>& res, bool is_load)
@ -434,8 +442,7 @@ void VFS::SaveLoadDevices(std::vector<VFSManagerEntry>& res, bool is_load)
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_flash/", "/dev_flash/"); res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_flash/", "/dev_flash/");
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb000/"); res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb000/");
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb/"); res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb/");
res.emplace_back(vfsDevice_LocalFile, "$(GameDir)", "/app_home/"); res.emplace_back(vfsDevice_LocalFile, "$(GameDir)/../../", "/dev_bdvd/");
res.emplace_back(vfsDevice_LocalFile, "$(GameDir)/../", "/dev_bdvd/");
res.emplace_back(vfsDevice_LocalFile, "", "/host_root/"); res.emplace_back(vfsDevice_LocalFile, "", "/host_root/");
return; return;

View file

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <map>
class vfsDevice; class vfsDevice;
struct vfsFileBase; struct vfsFileBase;
@ -51,18 +52,30 @@ struct VFS
std::string cwd; std::string cwd;
std::string FindEntry(const std::string &path);
//TODO: find out where these are supposed to be deleted or just make it shared_ptr //TODO: find out where these are supposed to be deleted or just make it shared_ptr
//and also make GetDevice and GetDeviceLocal return shared_ptr then. //and also make GetDevice and GetDeviceLocal return shared_ptr then.
// A vfsDevice will be deleted when they're unmounted or the VFS struct is destroyed. // A vfsDevice will be deleted when they're unmounted or the VFS struct is destroyed.
// This will cause problems if other code stores the pointer returned by GetDevice/GetDeviceLocal // This will cause problems if other code stores the pointer returned by GetDevice/GetDeviceLocal
// and tries to use it after the device is unmounted. // and tries to use it after the device is unmounted.
std::vector<vfsDevice *> m_devices; std::vector<vfsDevice *> m_devices;
struct links_sorter
{
bool operator()(const std::vector<std::string>& a, const std::vector<std::string>& b)
{
return b.size() < a.size();
}
};
std::map<std::vector<std::string>, std::vector<std::string>, links_sorter> links;
void Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device); void Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device);
void Link(const std::string& mount_point, const std::string& ps3_path);
void UnMount(const std::string& ps3_path); void UnMount(const std::string& ps3_path);
void UnMountAll(); void UnMountAll();
std::string GetLinked(std::string ps3_path) const;
vfsFileBase* OpenFile(const std::string& ps3_path, vfsOpenMode mode) const; vfsFileBase* OpenFile(const std::string& ps3_path, vfsOpenMode mode) const;
vfsDirBase* OpenDir(const std::string& ps3_path) const; vfsDirBase* OpenDir(const std::string& ps3_path) const;
bool CreateFile(const std::string& ps3_path) const; bool CreateFile(const std::string& ps3_path) const;

View file

@ -29,7 +29,7 @@ bool vfsDir::Open(const std::string& path)
DirEntryInfo info; DirEntryInfo info;
m_cwd = simplify_path(0 && m_stream && m_stream->IsOpened() ? m_stream->GetPath() : path, true); m_cwd = simplify_path(Emu.GetVFS().GetLinked(0 && m_stream && m_stream->IsOpened() ? m_stream->GetPath() : path), true);
auto blocks = simplify_path_blocks(GetPath()); auto blocks = simplify_path_blocks(GetPath());

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
class PPUThread; class CPUThread;
namespace vm namespace vm
{ {
@ -356,9 +356,9 @@ namespace vm
public: public:
typedef RT(*type)(T...); typedef RT(*type)(T...);
RT call(PPUThread& CPU, T... args) const; // call using specified PPU thread context, defined in Callback.h (CB_FUNC.h) RT call(CPUThread& CPU, T... args) const; // call using specified CPU thread context, defined in CB_FUNC.h
RT operator()(T... args) const; // call using current PPU thread context, defined in Callback.h (CB_FUNC.h) RT operator()(T... args) const; // call using current CPU thread context, defined in CB_FUNC.h
AT addr() const AT addr() const
{ {

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "Emu/Memory/atomic_type.h"
enum enum
{ {
CELL_GCM_DISPLAY_HSYNC = 1, CELL_GCM_DISPLAY_HSYNC = 1,
@ -201,9 +203,9 @@ enum
struct CellGcmControl struct CellGcmControl
{ {
be_t<u32> put; atomic_t<u32> put;
be_t<u32> get; atomic_t<u32> get;
be_t<u32> ref; atomic_t<u32> ref;
}; };
struct CellGcmConfig struct CellGcmConfig
@ -216,12 +218,16 @@ struct CellGcmConfig
be_t<u32> coreFrequency; be_t<u32> coreFrequency;
}; };
struct CellGcmContextData;
typedef s32(*CellGcmContextCallback)(vm::ptr<CellGcmContextData>, u32);
struct CellGcmContextData struct CellGcmContextData
{ {
be_t<u32> begin; be_t<u32> begin;
be_t<u32> end; be_t<u32> end;
be_t<u32> current; be_t<u32> current;
be_t<u32> callback; vm::bptr<CellGcmContextCallback> callback;
}; };
struct gcmInfo struct gcmInfo

View file

@ -7,6 +7,7 @@
#include "RSXThread.h" #include "RSXThread.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/Callback.h"
#include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/SysCalls/lv2/sys_time.h" #include "Emu/SysCalls/lv2/sys_time.h"
#define ARGS(x) (x >= count ? OutOfArgsCount(x, cmd, count, args.addr()) : args[x].ToLE()) #define ARGS(x) (x >= count ? OutOfArgsCount(x, cmd, count, args.addr()) : args[x].ToLE())
@ -258,7 +259,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const
// NV406E // NV406E
case NV406E_SET_REFERENCE: case NV406E_SET_REFERENCE:
{ {
m_ctrl->ref = ARGS(0); m_ctrl->ref.exchange(be_t<u32>::make(ARGS(0)));
} }
break; break;
@ -2203,14 +2204,8 @@ void RSXThread::Task()
inc=1; inc=1;
u32 put, get; u32 get = m_ctrl->get.read_sync();
// this code produces only mov + bswap: u32 put = m_ctrl->put.read_sync();
put = se_t<u32>::func(std::atomic_load((volatile std::atomic<u32>*)((u8*)m_ctrl + offsetof(CellGcmControl, put))));
get = se_t<u32>::func(std::atomic_load((volatile std::atomic<u32>*)((u8*)m_ctrl + offsetof(CellGcmControl, get))));
/*
se_t<u32>::func(put, InterlockedCompareExchange((volatile unsigned long*)((u8*)m_ctrl + offsetof(CellGcmControl, put)), 0, 0));
se_t<u32>::func(get, InterlockedCompareExchange((volatile unsigned long*)((u8*)m_ctrl + offsetof(CellGcmControl, get)), 0, 0));
*/
if(put == get || !Emu.IsRunning()) if(put == get || !Emu.IsRunning())
{ {
@ -2240,7 +2235,7 @@ void RSXThread::Task()
{ {
u32 addr = cmd & ~(CELL_GCM_METHOD_FLAG_JUMP | CELL_GCM_METHOD_FLAG_NON_INCREMENT); u32 addr = cmd & ~(CELL_GCM_METHOD_FLAG_JUMP | CELL_GCM_METHOD_FLAG_NON_INCREMENT);
//LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", addr, m_ioAddress + get, cmd, get, put); //LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", addr, m_ioAddress + get, cmd, get, put);
m_ctrl->get = addr; m_ctrl->get.exchange(be_t<u32>::make(addr));
continue; continue;
} }
if(cmd & CELL_GCM_METHOD_FLAG_CALL) if(cmd & CELL_GCM_METHOD_FLAG_CALL)
@ -2249,7 +2244,7 @@ void RSXThread::Task()
u32 offs = cmd & ~CELL_GCM_METHOD_FLAG_CALL; u32 offs = cmd & ~CELL_GCM_METHOD_FLAG_CALL;
//u32 addr = offs; //u32 addr = offs;
//LOG_WARNING(RSX, "rsx call(0x%x) #0x%x - 0x%x - 0x%x", offs, addr, cmd, get); //LOG_WARNING(RSX, "rsx call(0x%x) #0x%x - 0x%x - 0x%x", offs, addr, cmd, get);
m_ctrl->get = offs; m_ctrl->get.exchange(be_t<u32>::make(offs));
continue; continue;
} }
if(cmd == CELL_GCM_METHOD_FLAG_RETURN) if(cmd == CELL_GCM_METHOD_FLAG_RETURN)
@ -2258,7 +2253,7 @@ void RSXThread::Task()
u32 get = m_call_stack.top(); u32 get = m_call_stack.top();
m_call_stack.pop(); m_call_stack.pop();
//LOG_WARNING(RSX, "rsx return(0x%x)", get); //LOG_WARNING(RSX, "rsx return(0x%x)", get);
m_ctrl->get = get; m_ctrl->get.exchange(be_t<u32>::make(get));
continue; continue;
} }
if(cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT) if(cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT)
@ -2272,7 +2267,10 @@ void RSXThread::Task()
LOG_ERROR(Log::RSX, "null cmd: cmd=0x%x, put=0x%x, get=0x%x (addr=0x%x)", cmd, put, get, (u32)Memory.RSXIOMem.RealAddr(get)); LOG_ERROR(Log::RSX, "null cmd: cmd=0x%x, put=0x%x, get=0x%x (addr=0x%x)", cmd, put, get, (u32)Memory.RSXIOMem.RealAddr(get));
//Emu.Pause(); //Emu.Pause();
//HACK! We shouldn't be here //HACK! We shouldn't be here
m_ctrl->get = get + (count + 1) * 4; m_ctrl->get.atomic_op([](be_t<u32>& value)
{
value += 4;
});
continue; continue;
} }
@ -2285,7 +2283,10 @@ void RSXThread::Task()
DoCmd(cmd, cmd & 0x3ffff, args.addr(), count); DoCmd(cmd, cmd & 0x3ffff, args.addr(), count);
m_ctrl->get = get + (count + 1) * 4; m_ctrl->get.atomic_op([count](be_t<u32>& value)
{
value += (count + 1) * 4;
});
//memset(Memory.GetMemFromAddr(p.m_ioAddress + get), 0, (count + 1) * 4); //memset(Memory.GetMemFromAddr(p.m_ioAddress + get), 0, (count + 1) * 4);
} }
catch (const std::string& e) catch (const std::string& e)

View file

@ -3,7 +3,6 @@
#include "RSXTexture.h" #include "RSXTexture.h"
#include "RSXVertexProgram.h" #include "RSXVertexProgram.h"
#include "RSXFragmentProgram.h" #include "RSXFragmentProgram.h"
#include "Emu/SysCalls/Callback.h"
#include <stack> #include <stack>
#include "Utilities/SSemaphore.h" #include "Utilities/SSemaphore.h"

View file

@ -16,8 +16,8 @@ enum VideoErrorCode
enum CellVideoOut enum CellVideoOut
{ {
CELL_VIDEO_OUT_PRIMARY, CELL_VIDEO_OUT_PRIMARY = 0,
CELL_VIDEO_OUT_SECONDARY, CELL_VIDEO_OUT_SECONDARY = 1,
}; };
enum CellVideoOutResolutionId enum CellVideoOutResolutionId

View file

@ -165,12 +165,12 @@ namespace cb_detail
namespace vm namespace vm
{ {
template<typename AT, typename RT, typename... T> template<typename AT, typename RT, typename... T>
__forceinline RT _ptr_base<RT(*)(T...), 1, AT>::call(PPUThread& CPU, T... args) const __forceinline RT _ptr_base<RT(*)(T...), 1, AT>::call(CPUThread& CPU, T... args) const
{ {
const u32 pc = vm::get_ref<be_t<u32>>(m_addr); const u32 pc = vm::get_ref<be_t<u32>>(m_addr);
const u32 rtoc = vm::get_ref<be_t<u32>>(m_addr + 4); const u32 rtoc = vm::get_ref<be_t<u32>>(m_addr + 4);
return cb_detail::_func_caller<RT, T...>::call(CPU, pc, rtoc, args...); return cb_detail::_func_caller<RT, T...>::call(static_cast<PPUThread&>(CPU), pc, rtoc, args...);
} }
template<typename AT, typename RT, typename... T> template<typename AT, typename RT, typename... T>

View file

@ -1,10 +1,10 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "ErrorCodes.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "Emu/ARMv7/ARMv7Thread.h"
#include "Callback.h" #include "Callback.h"
void CallbackManager::Register(const std::function<s32()>& func) void CallbackManager::Register(const std::function<s32()>& func)
@ -51,14 +51,28 @@ void CallbackManager::Init()
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
m_cb_thread = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); if (Memory.PSV.RAM.GetStartAddr())
{
m_cb_thread = &Emu.GetCPU().AddThread(CPU_THREAD_ARMv7);
m_cb_thread->SetName("Callback Thread"); m_cb_thread->SetName("Callback Thread");
m_cb_thread->SetEntry(0); m_cb_thread->SetEntry(0);
m_cb_thread->SetPrio(1001); m_cb_thread->SetPrio(1001);
m_cb_thread->SetStackSize(0x10000); m_cb_thread->SetStackSize(0x10000);
m_cb_thread->InitStack(); m_cb_thread->InitStack();
m_cb_thread->InitRegs(); m_cb_thread->InitRegs();
m_cb_thread->DoRun(); static_cast<ARMv7Thread*>(m_cb_thread)->DoRun();
}
else
{
m_cb_thread = &Emu.GetCPU().AddThread(CPU_THREAD_PPU);
m_cb_thread->SetName("Callback Thread");
m_cb_thread->SetEntry(0);
m_cb_thread->SetPrio(1001);
m_cb_thread->SetStackSize(0x10000);
m_cb_thread->InitStack();
m_cb_thread->InitRegs();
static_cast<PPUThread*>(m_cb_thread)->DoRun();
}
thread cb_async_thread("CallbackManager::Async() thread", [this]() thread cb_async_thread("CallbackManager::Async() thread", [this]()
{ {

View file

@ -1,11 +1,12 @@
#pragma once #pragma once
#include "CB_FUNC.h"
class CPUThread;
class CallbackManager class CallbackManager
{ {
std::vector<std::function<s32()>> m_cb_list; std::vector<std::function<s32()>> m_cb_list;
std::vector<std::function<void()>> m_async_list; std::vector<std::function<void()>> m_async_list;
PPUThread* m_cb_thread; CPUThread* m_cb_thread;
std::mutex m_mutex; std::mutex m_mutex;
public: public:

View file

@ -81,6 +81,8 @@ void Module::Load()
{ {
Emu.GetModuleManager().AddFunc(i.second); Emu.GetModuleManager().AddFunc(i.second);
} }
SetLoaded(true);
} }
void Module::UnLoad() void Module::UnLoad()

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h"
extern std::mutex g_mutex_avcodec_open2; extern std::mutex g_mutex_avcodec_open2;

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
#include "cellPamf.h" #include "cellPamf.h"

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Utilities/rMsgBox.h" #include "Utilities/rMsgBox.h"
#include "Emu/FS/VFS.h" #include "Emu/FS/VFS.h"
@ -181,9 +181,8 @@ int cellGameContentPermit(vm::ptr<char[CELL_GAME_PATH_MAX]> contentInfoPath, vm:
cellGame->Warning("cellGameContentPermit(contentInfoPath_addr=0x%x, usrdirPath_addr=0x%x)", cellGame->Warning("cellGameContentPermit(contentInfoPath_addr=0x%x, usrdirPath_addr=0x%x)",
contentInfoPath.addr(), usrdirPath.addr()); contentInfoPath.addr(), usrdirPath.addr());
if (!contentInfoPath && !usrdirPath) if (!contentInfoPath || !usrdirPath)
{ {
cellGame->Warning("cellGameContentPermit(): CELL_GAME_ERROR_PARAM");
return CELL_GAME_ERROR_PARAM; return CELL_GAME_ERROR_PARAM;
} }

View file

@ -2,6 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/CB_FUNC.h"
#include "sysPrxForUser.h" #include "sysPrxForUser.h"
//#include "Emu/RSX/GCM.h" //#include "Emu/RSX/GCM.h"
@ -288,9 +289,11 @@ int cellGcmGetConfiguration(vm::ptr<CellGcmConfig> config)
int cellGcmGetFlipStatus() int cellGcmGetFlipStatus()
{ {
cellGcmSys->Log("cellGcmGetFlipStatus()"); int status = Emu.GetGSManager().GetRender().m_flip_status;
return Emu.GetGSManager().GetRender().m_flip_status; cellGcmSys->Log("cellGcmGetFlipStatus() -> %d", status);
return status;
} }
u32 cellGcmGetTiledPitchSize(u32 size) u32 cellGcmGetTiledPitchSize(u32 size)
@ -368,7 +371,7 @@ s32 _cellGcmInitBody(vm::ptr<CellGcmContextData> context, u32 cmdSize, u32 ioSiz
current_context.begin = ctx_begin; current_context.begin = ctx_begin;
current_context.end = ctx_begin + ctx_size; current_context.end = ctx_begin + ctx_size;
current_context.current = current_context.begin; current_context.current = current_context.begin;
current_context.callback = Emu.GetRSXCallback() - 4; current_context.callback.set(be_t<u32>::make(Emu.GetRSXCallback() - 4));
gcm_info.context_addr = (u32)Memory.MainMem.AllocAlign(0x1000); gcm_info.context_addr = (u32)Memory.MainMem.AllocAlign(0x1000);
gcm_info.control_addr = gcm_info.context_addr + 0x40; gcm_info.control_addr = gcm_info.context_addr + 0x40;
@ -377,9 +380,9 @@ s32 _cellGcmInitBody(vm::ptr<CellGcmContextData> context, u32 cmdSize, u32 ioSiz
vm::write32(context.addr(), gcm_info.context_addr); vm::write32(context.addr(), gcm_info.context_addr);
auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr); auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr);
ctrl.put = 0; ctrl.put.write_relaxed(be_t<u32>::make(0));
ctrl.get = 0; ctrl.get.write_relaxed(be_t<u32>::make(0));
ctrl.ref = -1; ctrl.ref.write_relaxed(be_t<u32>::make(-1));
auto& render = Emu.GetGSManager().GetRender(); auto& render = Emu.GetGSManager().GetRender();
render.m_ctxt_addr = context.addr(); render.m_ctxt_addr = context.addr();
@ -498,25 +501,21 @@ s32 cellGcmSetPrepareFlip(vm::ptr<CellGcmContextData> ctxt, u32 id)
GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH); GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH);
u32 current = ctxt->current; u32 current = ctxt->current;
u32 end = ctxt->end;
if(current + 8 >= end) if (current + 8 == ctxt->begin)
{ {
cellGcmSys->Error("bad flip!"); cellGcmSys->Error("cellGcmSetPrepareFlip : queue is full");
//cellGcmCallback(ctxt.addr(), current + 8 - end); return CELL_GCM_ERROR_FAILURE;
//copied: }
auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr); if (current + 8 >= ctxt->end)
{
const s32 res = ctxt->current - ctxt->begin - ctrl.put; cellGcmSys->Error("Bad flip!");
if (s32 res = ctxt->callback(ctxt, 8 /* ??? */))
memmove(vm::get_ptr<void>(ctxt->begin), vm::get_ptr<void>(ctxt->current - res), res); {
cellGcmSys->Error("cellGcmSetPrepareFlip : callback failed (0x%08x)", res);
ctxt->current = ctxt->begin + res; return res;
}
//InterlockedExchange64((volatile long long*)((u8*)&ctrl + offsetof(CellGcmControl, put)), (u64)(u32)re(res));
ctrl.put = res;
ctrl.get = 0;
} }
current = ctxt->current; current = ctxt->current;
@ -527,7 +526,10 @@ s32 cellGcmSetPrepareFlip(vm::ptr<CellGcmContextData> ctxt, u32 id)
if(ctxt.addr() == gcm_info.context_addr) if(ctxt.addr() == gcm_info.context_addr)
{ {
auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr); auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr);
ctrl.put += 8; ctrl.put.atomic_op([](be_t<u32>& value)
{
value += 8;
});
} }
return id; return id;
@ -1164,25 +1166,38 @@ int cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co
// TODO: This function was originally located in lv2/SC_GCM and appears in RPCS3 as a lv2 syscall with id 1023, // TODO: This function was originally located in lv2/SC_GCM and appears in RPCS3 as a lv2 syscall with id 1023,
// which according to lv2 dumps isn't the case. So, is this a proper place for this function? // which according to lv2 dumps isn't the case. So, is this a proper place for this function?
int cellGcmCallback(u32 context_addr, u32 count) s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count)
{ {
cellGcmSys->Log("cellGcmCallback(context_addr=0x%x, count=0x%x)", context_addr, count); cellGcmSys->Log("cellGcmCallback(context_addr=0x%x, count=0x%x)", context.addr(), count);
GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH);
auto& ctx = vm::get_ref<CellGcmContextData>(context_addr);
auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr); auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr);
const s32 res = ctx.current - ctx.begin - ctrl.put; {
const u32 address = context->current;
const u32 upper = offsetTable.ioAddress[address >> 20]; // 12 bits
assert(upper != 0xFFFF);
const u32 offset = (upper << 20) | (address & 0xFFFFF);
//ctrl.put.exchange(be_t<u32>::make(offset)); // update put pointer
}
memmove(vm::get_ptr<void>(ctx.begin), vm::get_ptr<void>(ctx.current - res), res); // preparations for changing the place (for optimized FIFO mode)
//auto cmd = vm::ptr<u32>::make(context->current.ToLE());
//cmd[0] = 0x41D6C;
//cmd[1] = 0x20;
//cmd[2] = 0x41D74;
//cmd[3] = 0; // some incrementing by module value
//context->current += 0x10;
ctx.current = ctx.begin + res; {
const u32 address = context->begin;
//InterlockedExchange64((volatile long long*)((u8*)&ctrl + offsetof(CellGcmControl, put)), (u64)(u32)re(res)); const u32 upper = offsetTable.ioAddress[address >> 20]; // 12 bits
ctrl.put = res; assert(upper != 0xFFFF);
ctrl.get = 0; const u32 offset = (upper << 20) | (address & 0xFFFFF);
vm::write32(context->current, CELL_GCM_METHOD_FLAG_JUMP | offset); // set JUMP cmd
}
context->current = context->begin; // rewind to the beginning
// TODO: something is missing
return CELL_OK; return CELL_OK;
} }

View file

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "Emu/RSX/GCM.h"
enum enum
{ {
@ -20,8 +21,7 @@ struct CellGcmOffsetTable
void InitOffsetTable(); void InitOffsetTable();
u32 gcmGetLocalMemorySize(); u32 gcmGetLocalMemorySize();
// libgcm functions
// SysCalls
s32 cellGcmSetPrepareFlip(vm::ptr<CellGcmContextData> ctxt, u32 id); s32 cellGcmSetPrepareFlip(vm::ptr<CellGcmContextData> ctxt, u32 id);
s32 cellGcmAddressToOffset(u64 address, vm::ptr<be_t<u32>> offset); s32 cellGcmAddressToOffset(u64 address, vm::ptr<be_t<u32>> offset);
@ -35,3 +35,6 @@ s32 cellGcmReserveIoMapSize(u32 size);
s32 cellGcmUnmapEaIoAddress(u64 ea); s32 cellGcmUnmapEaIoAddress(u64 ea);
s32 cellGcmUnmapIoAddress(u64 io); s32 cellGcmUnmapIoAddress(u64 io);
s32 cellGcmUnreserveIoMapSize(u32 size); s32 cellGcmUnreserveIoMapSize(u32 size);
// Syscall
s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count);

View file

@ -3,6 +3,7 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/Callback.h"
#include "Emu/SysCalls/CB_FUNC.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Utilities/rMsgBox.h" #include "Utilities/rMsgBox.h"

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/FS/VFS.h" #include "Emu/FS/VFS.h"
#include "Emu/FS/vfsFile.h" #include "Emu/FS/vfsFile.h"

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/SysCalls/lv2/sys_ppu_thread.h" #include "Emu/SysCalls/lv2/sys_ppu_thread.h"
@ -953,7 +953,7 @@ s64 cellSpursAttributeEnableSystemWorkload(vm::ptr<CellSpursAttribute> attr, vm:
s64 cellSpursFinalize(vm::ptr<CellSpurs> spurs) s64 cellSpursFinalize(vm::ptr<CellSpurs> spurs)
{ {
cellSpurs->Warning("cellSpursFinalize(spurs_addr=0x%x)", spurs.addr()); cellSpurs->Todo("cellSpursFinalize(spurs_addr=0x%x)", spurs.addr());
#ifdef PRX_DEBUG_XXX #ifdef PRX_DEBUG_XXX
return GetCurrentPPUThread().FastCall2(libsre + 0x8568, libsre_rtoc); return GetCurrentPPUThread().FastCall2(libsre + 0x8568, libsre_rtoc);
#endif #endif

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/SysCalls/lv2/sys_process.h" #include "Emu/SysCalls/lv2/sys_process.h"
#include "Emu/Event.h" #include "Emu/Event.h"

View file

@ -4,6 +4,7 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/Callback.h"
#include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/DbgCommand.h" #include "Emu/DbgCommand.h"
#include "rpcs3/Ini.h" #include "rpcs3/Ini.h"

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h"
std::mutex g_mutex_avcodec_open2; std::mutex g_mutex_avcodec_open2;

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Audio/cellAudio.h" #include "Emu/Audio/cellAudio.h"

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "rpcs3/Ini.h" #include "rpcs3/Ini.h"
#include "Utilities/rXml.h" #include "Utilities/rXml.h"

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/FS/vfsFile.h" #include "Emu/FS/vfsFile.h"
#include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_spu.h"

View file

@ -3,6 +3,7 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/Callback.h"
#include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/FS/VFS.h" #include "Emu/FS/VFS.h"
#include "Emu/FS/vfsFileBase.h" #include "Emu/FS/vfsFileBase.h"

View file

@ -26,6 +26,8 @@
#include "lv2/sys_tty.h" #include "lv2/sys_tty.h"
#include "lv2/sys_vm.h" #include "lv2/sys_vm.h"
#include "Emu/SysCalls/Modules/cellGcmSys.h"
#include "SysCalls.h" #include "SysCalls.h"
namespace detail{ namespace detail{
@ -40,8 +42,6 @@ static func_caller *null_func = bind_func(default_syscall);
static const int kSyscallTableLength = 1024; static const int kSyscallTableLength = 1024;
extern int cellGcmCallback(u32 context_addr, u32 count);
// UNS = Unused // UNS = Unused
// ROOT = Root // ROOT = Root
// DBG = Debug // DBG = Debug

View file

@ -40,7 +40,7 @@ s32 cellFsOpen(vm::ptr<const char> path, s32 flags, vm::ptr<be_t<u32>> fd, vm::p
LV2_LOCK(0); LV2_LOCK(0);
s32 _oflags = flags; s32 _oflags = flags;
if(flags & CELL_O_CREAT) if (flags & CELL_O_CREAT)
{ {
_oflags &= ~CELL_O_CREAT; _oflags &= ~CELL_O_CREAT;
Emu.GetVFS().CreateFile(_path); Emu.GetVFS().CreateFile(_path);
@ -48,7 +48,7 @@ s32 cellFsOpen(vm::ptr<const char> path, s32 flags, vm::ptr<be_t<u32>> fd, vm::p
vfsOpenMode o_mode; vfsOpenMode o_mode;
switch(flags & CELL_O_ACCMODE) switch (flags & CELL_O_ACCMODE)
{ {
case CELL_O_RDONLY: case CELL_O_RDONLY:
_oflags &= ~CELL_O_RDONLY; _oflags &= ~CELL_O_RDONLY;
@ -88,7 +88,7 @@ s32 cellFsOpen(vm::ptr<const char> path, s32 flags, vm::ptr<be_t<u32>> fd, vm::p
break; break;
} }
if(_oflags != 0) if (_oflags != 0)
{ {
sys_fs->Error("\"%s\" has unknown flags! flags: 0x%08x", path.get_ptr(), flags); sys_fs->Error("\"%s\" has unknown flags! flags: 0x%08x", path.get_ptr(), flags);
return CELL_EINVAL; return CELL_EINVAL;
@ -102,7 +102,7 @@ s32 cellFsOpen(vm::ptr<const char> path, s32 flags, vm::ptr<be_t<u32>> fd, vm::p
vfsFileBase* stream = Emu.GetVFS().OpenFile(_path, o_mode); vfsFileBase* stream = Emu.GetVFS().OpenFile(_path, o_mode);
if(!stream || !stream->IsOpened()) if (!stream || !stream->IsOpened())
{ {
delete stream; delete stream;
sys_fs->Error("\"%s\" not found! flags: 0x%08x", path.get_ptr(), flags); sys_fs->Error("\"%s\" not found! flags: 0x%08x", path.get_ptr(), flags);
@ -124,9 +124,11 @@ s32 cellFsRead(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<be_t<u64>> nread)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
if (nbytes != (u32)nbytes) return CELL_ENOMEM; if (nbytes != (u32)nbytes)
return CELL_ENOMEM;
// TODO: checks // TODO: checks
@ -145,7 +147,7 @@ s32 cellFsWrite(u32 fd, vm::ptr<const void> buf, u64 nbytes, vm::ptr<u64> nwrite
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
if (nbytes != (u32)nbytes) return CELL_ENOMEM; if (nbytes != (u32)nbytes) return CELL_ENOMEM;
@ -164,7 +166,7 @@ s32 cellFsClose(u32 fd)
LV2_LOCK(0); LV2_LOCK(0);
if(!Emu.GetIdManager().RemoveID(fd)) if (!Emu.GetIdManager().RemoveID(fd))
return CELL_ESRCH; return CELL_ESRCH;
return CELL_OK; return CELL_OK;
@ -177,7 +179,7 @@ s32 cellFsOpendir(vm::ptr<const char> path, vm::ptr<u32> fd)
LV2_LOCK(0); LV2_LOCK(0);
vfsDirBase* dir = Emu.GetVFS().OpenDir(path.get_ptr()); vfsDirBase* dir = Emu.GetVFS().OpenDir(path.get_ptr());
if(!dir || !dir->IsOpened()) if (!dir || !dir->IsOpened())
{ {
delete dir; delete dir;
return CELL_ENOENT; return CELL_ENOENT;
@ -194,11 +196,11 @@ s32 cellFsReaddir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
LV2_LOCK(0); LV2_LOCK(0);
vfsDirBase* directory; vfsDirBase* directory;
if(!sys_fs->CheckId(fd, directory)) if (!sys_fs->CheckId(fd, directory))
return CELL_ESRCH; return CELL_ESRCH;
const DirEntryInfo* info = directory->Read(); const DirEntryInfo* info = directory->Read();
if(info) if (info)
{ {
dir->d_type = (info->flags & DirEntry_TypeFile) ? CELL_FS_TYPE_REGULAR : CELL_FS_TYPE_DIRECTORY; dir->d_type = (info->flags & DirEntry_TypeFile) ? CELL_FS_TYPE_REGULAR : CELL_FS_TYPE_DIRECTORY;
dir->d_namlen = u8(std::min((u32)info->name.length(), (u32)CELL_MAX_FS_FILE_NAME_LENGTH)); dir->d_namlen = u8(std::min((u32)info->name.length(), (u32)CELL_MAX_FS_FILE_NAME_LENGTH));
@ -219,7 +221,7 @@ s32 cellFsClosedir(u32 fd)
LV2_LOCK(0); LV2_LOCK(0);
if(!Emu.GetIdManager().RemoveID(fd)) if (!Emu.GetIdManager().RemoveID(fd))
return CELL_ESRCH; return CELL_ESRCH;
return CELL_OK; return CELL_OK;
@ -276,9 +278,8 @@ s32 cellFsFstat(u32 fd, vm::ptr<CellFsStat> sb)
IDType type; IDType type;
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE) { if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE)
return CELL_ESRCH; return CELL_ESRCH;
}
sb->st_mode = sb->st_mode =
CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR | CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR |
@ -305,9 +306,10 @@ s32 cellFsMkdir(vm::ptr<const char> path, u32 mode)
const std::string _path = path.get_ptr(); const std::string _path = path.get_ptr();
if(vfsDir().IsExists(_path)) if (vfsDir().IsExists(_path))
return CELL_EEXIST; return CELL_EEXIST;
if(!Emu.GetVFS().CreateDir(_path))
if (!Emu.GetVFS().CreateDir(_path))
return CELL_EBUSY; return CELL_EBUSY;
return CELL_OK; return CELL_OK;
@ -378,10 +380,10 @@ s32 cellFsRmdir(vm::ptr<const char> path)
std::string _path = path.get_ptr(); std::string _path = path.get_ptr();
vfsDir d; vfsDir d;
if(!d.IsExists(_path)) if (!d.IsExists(_path))
return CELL_ENOENT; return CELL_ENOENT;
if(!d.Remove(_path)) if (!d.Remove(_path))
return CELL_EBUSY; return CELL_EBUSY;
return CELL_OK; return CELL_OK;
@ -426,9 +428,9 @@ s32 cellFsLseek(u32 fd, s64 offset, u32 whence, vm::ptr<be_t<u64>> pos)
IDType type; IDType type;
vfsStream* file; vfsStream* file;
if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE) { if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE)
return CELL_ESRCH; return CELL_ESRCH;
}
*pos = file->Seek(offset, seek_mode); *pos = file->Seek(offset, seek_mode);
return CELL_OK; return CELL_OK;
} }
@ -441,9 +443,9 @@ s32 cellFsFtruncate(u32 fd, u64 size)
IDType type; IDType type;
vfsStream* file; vfsStream* file;
if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE) { if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE)
return CELL_ESRCH; return CELL_ESRCH;
}
u64 initialSize = file->GetSize(); u64 initialSize = file->GetSize();
if (initialSize < size) if (initialSize < size)
@ -471,7 +473,7 @@ s32 cellFsTruncate(vm::ptr<const char> path, u64 size)
LV2_LOCK(0); LV2_LOCK(0);
vfsFile f(path.get_ptr(), vfsReadWrite); vfsFile f(path.get_ptr(), vfsReadWrite);
if(!f.IsOpened()) if (!f.IsOpened())
{ {
sys_fs->Warning("cellFsTruncate: \"%s\" not found.", path.get_ptr()); sys_fs->Warning("cellFsTruncate: \"%s\" not found.", path.get_ptr());
return CELL_ENOENT; return CELL_ENOENT;
@ -504,7 +506,8 @@ s32 cellFsFGetBlockSize(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_siz
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
*sector_size = 4096; // ? *sector_size = 4096; // ?
*block_size = 4096; // ? *block_size = 4096; // ?
@ -547,11 +550,11 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr<CellFsDirectoryEntry> entries, u32
LV2_LOCK(0); LV2_LOCK(0);
vfsDirBase* directory; vfsDirBase* directory;
if(!sys_fs->CheckId(fd, directory)) if (!sys_fs->CheckId(fd, directory))
return CELL_ESRCH; return CELL_ESRCH;
const DirEntryInfo* info = directory->Read(); const DirEntryInfo* info = directory->Read();
if(info) if (info)
{ {
entries->attribute.st_mode = entries->attribute.st_mode =
CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR | CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR |
@ -585,17 +588,16 @@ s32 cellFsStReadInit(u32 fd, vm::ptr<CellFsRingBuffer> ringbuf)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
fs_config.m_ring_buffer = *ringbuf; fs_config.m_ring_buffer = *ringbuf;
// If the size is less than 1MB // If the size is less than 1MB
if(ringbuf->ringbuf_size < 0x40000000) { if (ringbuf->ringbuf_size < 0x40000000)
fs_config.m_alloc_mem_size = (((u32)ringbuf->ringbuf_size + 64 * 1024 - 1) / (64 * 1024)) * (64 * 1024); fs_config.m_alloc_mem_size = (((u32)ringbuf->ringbuf_size + 64 * 1024 - 1) / (64 * 1024)) * (64 * 1024);
} else
else {
fs_config.m_alloc_mem_size = (((u32)ringbuf->ringbuf_size + 1024 * 1024 - 1) / (1024 * 1024)) * (1024 * 1024); fs_config.m_alloc_mem_size = (((u32)ringbuf->ringbuf_size + 1024 * 1024 - 1) / (1024 * 1024)) * (1024 * 1024);
}
// alloc memory // alloc memory
fs_config.m_buffer = (u32)Memory.Alloc(fs_config.m_alloc_mem_size, 1024); fs_config.m_buffer = (u32)Memory.Alloc(fs_config.m_alloc_mem_size, 1024);
@ -613,7 +615,8 @@ s32 cellFsStReadFinish(u32 fd)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
Memory.Free(fs_config.m_buffer); Memory.Free(fs_config.m_buffer);
fs_config.m_fs_status = CELL_FS_ST_NOT_INITIALIZED; fs_config.m_fs_status = CELL_FS_ST_NOT_INITIALIZED;
@ -628,7 +631,8 @@ s32 cellFsStReadGetRingBuf(u32 fd, vm::ptr<CellFsRingBuffer> ringbuf)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
*ringbuf = fs_config.m_ring_buffer; *ringbuf = fs_config.m_ring_buffer;
@ -644,7 +648,8 @@ s32 cellFsStReadGetStatus(u32 fd, vm::ptr<u64> status)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
*status = fs_config.m_fs_status; *status = fs_config.m_fs_status;
@ -658,7 +663,8 @@ s32 cellFsStReadGetRegid(u32 fd, vm::ptr<u64> regid)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
*regid = fs_config.m_regid; *regid = fs_config.m_regid;
@ -672,7 +678,8 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
fs_config.m_current_addr = fs_config.m_buffer + (u32)offset; fs_config.m_current_addr = fs_config.m_buffer + (u32)offset;
fs_config.m_fs_status = CELL_FS_ST_PROGRESS; fs_config.m_fs_status = CELL_FS_ST_PROGRESS;
@ -687,7 +694,8 @@ s32 cellFsStReadStop(u32 fd)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
fs_config.m_fs_status = CELL_FS_ST_STOP; fs_config.m_fs_status = CELL_FS_ST_STOP;
@ -701,7 +709,8 @@ s32 cellFsStRead(u32 fd, u32 buf_addr, u64 size, vm::ptr<u64> rsize)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
// TODO: use ringbuffer (fs_config) // TODO: use ringbuffer (fs_config)
fs_config.m_regid += size; fs_config.m_regid += size;
@ -721,7 +730,8 @@ s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr<u32> addr, vm::ptr<u64> size)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
return CELL_OK; return CELL_OK;
} }
@ -733,7 +743,8 @@ s32 cellFsStReadPutCurrentAddr(u32 fd, u32 addr_addr, u64 size)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
return CELL_OK; return CELL_OK;
} }
@ -745,7 +756,8 @@ s32 cellFsStReadWait(u32 fd, u64 size)
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
return CELL_OK; return CELL_OK;
} }
@ -757,7 +769,8 @@ s32 cellFsStReadWaitCallback(u32 fd, u64 size, vm::ptr<void (*)(int xfd, u64 xsi
LV2_LOCK(0); LV2_LOCK(0);
vfsStream* file; vfsStream* file;
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (!sys_fs->CheckId(fd, file))
return CELL_ESRCH;
return CELL_OK; return CELL_OK;
} }

View file

@ -30,9 +30,7 @@ u32 EventFlag::check()
} }
if (m_protocol == SYS_SYNC_PRIORITY) if (m_protocol == SYS_SYNC_PRIORITY)
{
target = sq.pop_prio(); target = sq.pop_prio();
}
return target; return target;
} }
@ -42,13 +40,13 @@ s32 sys_event_flag_create(vm::ptr<u32> eflag_id, vm::ptr<sys_event_flag_attr> at
sys_event_flag.Warning("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)", sys_event_flag.Warning("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)",
eflag_id.addr(), attr.addr(), init); eflag_id.addr(), attr.addr(), init);
if (eflag_id.addr() == NULL) if (!eflag_id)
{ {
sys_event_flag.Error("sys_event_flag_create(): invalid memory access (eflag_id_addr=0x%x)", eflag_id.addr()); sys_event_flag.Error("sys_event_flag_create(): invalid memory access (eflag_id_addr=0x%x)", eflag_id.addr());
return CELL_EFAULT; return CELL_EFAULT;
} }
if (attr.addr() == NULL) if (!attr)
{ {
sys_event_flag.Error("sys_event_flag_create(): invalid memory access (attr_addr=0x%x)", attr.addr()); sys_event_flag.Error("sys_event_flag_create(): invalid memory access (attr_addr=0x%x)", attr.addr());
return CELL_EFAULT; return CELL_EFAULT;
@ -64,9 +62,7 @@ s32 sys_event_flag_create(vm::ptr<u32> eflag_id, vm::ptr<sys_event_flag_attr> at
} }
if (attr->pshared.ToBE() != se32(0x200)) if (attr->pshared.ToBE() != se32(0x200))
{
return CELL_EINVAL; return CELL_EINVAL;
}
switch (attr->type.ToBE()) switch (attr->type.ToBE())
{ {
@ -370,7 +366,7 @@ s32 sys_event_flag_get(u32 eflag_id, vm::ptr<u64> flags)
{ {
sys_event_flag.Log("sys_event_flag_get(eflag_id=%d, flags_addr=0x%x)", eflag_id, flags.addr()); sys_event_flag.Log("sys_event_flag_get(eflag_id=%d, flags_addr=0x%x)", eflag_id, flags.addr());
if (flags.addr() == NULL) if (!flags)
{ {
sys_event_flag.Error("sys_event_flag_create(): invalid memory access (flags_addr=0x%x)", flags.addr()); sys_event_flag.Error("sys_event_flag_create(): invalid memory access (flags_addr=0x%x)", flags.addr());
return CELL_EFAULT; return CELL_EFAULT;

View file

@ -28,7 +28,7 @@ s32 sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr)
default: return CELL_EINVAL; default: return CELL_EINVAL;
} }
if(!addr) if (!addr)
return CELL_ENOMEM; return CELL_ENOMEM;
// Write back the start address of the allocated area. // Write back the start address of the allocated area.

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"

View file

@ -73,16 +73,27 @@ void sys_game_process_exitspawn(
envp++; envp++;
} }
for (auto &arg : argv){ for (auto &arg : argv) {
sys_process.Log("argument: %s", arg.c_str()); sys_process.Log("argument: %s", arg.c_str());
} }
for (auto &en : env){
for (auto &en : env) {
sys_process.Log("env_argument: %s", en.c_str()); sys_process.Log("env_argument: %s", en.c_str());
} }
//TODO: execute the file in <path> with the args in argv //TODO: execute the file in <path> with the args in argv
//and the environment parameters in envp and copy the data //and the environment parameters in envp and copy the data
//from data_addr into the adress space of the new process //from data_addr into the adress space of the new process
//then kill the current process //then kill the current process
Emu.Pause();
sys_process.Success("Process finished");
CallAfter([]()
{
Emu.Stop();
});
return; return;
} }
@ -121,16 +132,27 @@ void sys_game_process_exitspawn2(
envp++; envp++;
} }
for (auto &arg : argv){ for (auto &arg : argv) {
sys_process.Log("argument: %s", arg.c_str()); sys_process.Log("argument: %s", arg.c_str());
} }
for (auto &en : env){
for (auto &en : env) {
sys_process.Log("env_argument: %s", en.c_str()); sys_process.Log("env_argument: %s", en.c_str());
} }
//TODO: execute the file in <path> with the args in argv //TODO: execute the file in <path> with the args in argv
//and the environment parameters in envp and copy the data //and the environment parameters in envp and copy the data
//from data_addr into the adress space of the new process //from data_addr into the adress space of the new process
//then kill the current process //then kill the current process
Emu.Pause();
sys_process.Success("Process finished");
CallAfter([]()
{
Emu.Stop();
});
return; return;
} }

View file

@ -15,6 +15,7 @@
#include "Emu/DbgCommand.h" #include "Emu/DbgCommand.h"
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
#include "Emu/SysCalls/Callback.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/Io/Pad.h" #include "Emu/Io/Pad.h"
#include "Emu/Io/Keyboard.h" #include "Emu/Io/Keyboard.h"
@ -202,7 +203,7 @@ void Emulator::Load()
} }
LOG_NOTICE(LOADER, " ");//used to be skip_line LOG_NOTICE(LOADER, " ");//used to be skip_line
vfsFile sfo("/app_home/PARAM.SFO"); vfsFile sfo("/app_home/../PARAM.SFO");
PSFLoader psf(sfo); PSFLoader psf(sfo);
psf.Load(false); psf.Load(false);
std::string title = psf.GetString("TITLE"); std::string title = psf.GetString("TITLE");
@ -211,7 +212,7 @@ void Emulator::Load()
LOG_NOTICE(LOADER, "Serial: %s", title_id.c_str()); LOG_NOTICE(LOADER, "Serial: %s", title_id.c_str());
// bdvd inserting imitation // bdvd inserting imitation
vfsFile f1("/app_home/dev_bdvd.path"); vfsFile f1("/app_home/../dev_bdvd.path");
if (f1.IsOpened()) if (f1.IsOpened())
{ {
std::string bdvd; std::string bdvd;
@ -245,7 +246,7 @@ void Emulator::Load()
} }
// trying to load some info from PARAM.SFO // trying to load some info from PARAM.SFO
vfsFile f2("/app_home/PARAM.SFO"); vfsFile f2("/app_home/../PARAM.SFO");
if (f2.IsOpened()) if (f2.IsOpened())
{ {
PSFLoader psf(f2); PSFLoader psf(f2);

View file

@ -84,7 +84,8 @@ class Emulator
uint m_mode; uint m_mode;
u32 m_rsx_callback; u32 m_rsx_callback;
u32 m_ppu_thr_exit; u32 m_cpu_thr_exit;
u32 m_cpu_thr_stop;
std::vector<std::unique_ptr<ModuleInitializer>> m_modules_init; std::vector<std::unique_ptr<ModuleInitializer>> m_modules_init;
std::vector<u64> m_break_points; std::vector<u64> m_break_points;
@ -114,7 +115,6 @@ public:
std::string m_elf_path; std::string m_elf_path;
std::string m_emu_path; std::string m_emu_path;
std::string m_title_id; std::string m_title_id;
u32 m_ppu_thr_stop;
s32 m_sdk_version; s32 m_sdk_version;
Emulator(); Emulator();
@ -172,14 +172,14 @@ public:
m_rsx_callback = addr; m_rsx_callback = addr;
} }
void SetPPUThreadExit(u32 addr) void SetCPUThreadExit(u32 addr)
{ {
m_ppu_thr_exit = addr; m_cpu_thr_exit = addr;
} }
void SetPPUThreadStop(u32 addr) void SetCPUThreadStop(u32 addr)
{ {
m_ppu_thr_stop = addr; m_cpu_thr_stop = addr;
} }
EmuInfo& GetInfo() { return m_info; } EmuInfo& GetInfo() { return m_info; }
@ -191,7 +191,8 @@ public:
u32 GetMallocPageSize() { return m_info.GetProcParam().malloc_pagesize; } u32 GetMallocPageSize() { return m_info.GetProcParam().malloc_pagesize; }
u32 GetRSXCallback() const { return m_rsx_callback; } u32 GetRSXCallback() const { return m_rsx_callback; }
u32 GetPPUThreadExit() const { return m_ppu_thr_exit; } u32 GetCPUThreadExit() const { return m_cpu_thr_exit; }
u32 GetCPUThreadStop() const { return m_cpu_thr_stop; }
void CheckStatus(); void CheckStatus();
bool BootGame(const std::string& path); bool BootGame(const std::string& path);

View file

@ -146,7 +146,7 @@ void KernelExplorer::Update()
sprintf(name, "Modules (%d)", count); sprintf(name, "Modules (%d)", count);
const auto& node = m_tree->AppendItem(root, name); const auto& node = m_tree->AppendItem(root, name);
const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_PRX); const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_PRX);
sprintf(name, "Segment List (%d)", 2 * objects.size()); // TODO: Assuming 2 segments per PRX file is not good sprintf(name, "Segment List (%l)", 2 * objects.size()); // TODO: Assuming 2 segments per PRX file is not good
m_tree->AppendItem(node, name); m_tree->AppendItem(node, name);
for (const auto& id : objects) for (const auto& id : objects)
{ {

View file

@ -332,7 +332,7 @@ void RSXDebugger::GoToGet(wxCommandEvent& event)
if (!RSXReady()) return; if (!RSXReady()) return;
auto ctrl = vm::get_ptr<CellGcmControl>(Emu.GetGSManager().GetRender().m_ctrlAddress); auto ctrl = vm::get_ptr<CellGcmControl>(Emu.GetGSManager().GetRender().m_ctrlAddress);
u64 realAddr; u64 realAddr;
if (Memory.RSXIOMem.getRealAddr(ctrl->get, realAddr)) { if (Memory.RSXIOMem.getRealAddr(ctrl->get.read_relaxed(), realAddr)) {
m_addr = realAddr; // WARNING: Potential Truncation? Cast from u64 to u32 m_addr = realAddr; // WARNING: Potential Truncation? Cast from u64 to u32
t_addr->SetValue(wxString::Format("%08x", m_addr)); t_addr->SetValue(wxString::Format("%08x", m_addr));
UpdateInformation(); UpdateInformation();
@ -346,7 +346,7 @@ void RSXDebugger::GoToPut(wxCommandEvent& event)
if (!RSXReady()) return; if (!RSXReady()) return;
auto ctrl = vm::get_ptr<CellGcmControl>(Emu.GetGSManager().GetRender().m_ctrlAddress); auto ctrl = vm::get_ptr<CellGcmControl>(Emu.GetGSManager().GetRender().m_ctrlAddress);
u64 realAddr; u64 realAddr;
if (Memory.RSXIOMem.getRealAddr(ctrl->put, realAddr)) { if (Memory.RSXIOMem.getRealAddr(ctrl->put.read_relaxed(), realAddr)) {
m_addr = realAddr; // WARNING: Potential Truncation? Cast from u64 to u32 m_addr = realAddr; // WARNING: Potential Truncation? Cast from u64 to u32
t_addr->SetValue(wxString::Format("%08x", m_addr)); t_addr->SetValue(wxString::Format("%08x", m_addr));
UpdateInformation(); UpdateInformation();

View file

@ -6,6 +6,7 @@
#include "ELF32.h" #include "ELF32.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/ARMv7/ARMv7Thread.h" #include "Emu/ARMv7/ARMv7Thread.h"
#include "Emu/ARMv7/PSVFuncList.h"
#include "Emu/System.h" #include "Emu/System.h"
namespace loader namespace loader
@ -43,6 +44,7 @@ namespace loader
m_phdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum); m_phdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum);
m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_phoff : m_ehdr.data_be.e_phoff)); m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_phoff : m_ehdr.data_be.e_phoff));
size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum) * sizeof(phdr); size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum) * sizeof(phdr);
if (m_stream->Read(m_phdrs.data(), size) != size) if (m_stream->Read(m_phdrs.data(), size) != size)
return broken_file; return broken_file;
} }
@ -51,9 +53,9 @@ namespace loader
if (m_ehdr.data_le.e_shnum) if (m_ehdr.data_le.e_shnum)
{ {
m_phdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum); m_shdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum);
m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_shoff : m_ehdr.data_be.e_shoff)); m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_shoff : m_ehdr.data_be.e_shoff));
size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum) * sizeof(phdr); size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum) * sizeof(phdr);
if (m_stream->Read(m_shdrs.data(), size) != size) if (m_stream->Read(m_shdrs.data(), size) != size)
return broken_file; return broken_file;
@ -85,7 +87,29 @@ namespace loader
switch (machine) switch (machine)
{ {
case MACHINE_MIPS: break; case MACHINE_MIPS: break;
case MACHINE_ARM: arm7_thread(m_ehdr.is_le() ? m_ehdr.data_le.e_entry : m_ehdr.data_be.e_entry, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); break; case MACHINE_ARM:
{
list_known_psv_modules();
auto armv7_thr_stop_data = vm::psv::ptr<u32>::make(Memory.PSV.RAM.AllocAlign(3 * 4));
armv7_thr_stop_data[0] = 0xf870; // HACK
armv7_thr_stop_data[1] = 0x0001; // index 1
Emu.SetCPUThreadExit(armv7_thr_stop_data.addr());
u32 entry = m_ehdr.data_le.e_entry + (u32)Memory.PSV.RAM.GetStartAddr();
auto code = vm::psv::ptr<const u32>::make(entry & ~3);
// very rough way to find entry point in .sceModuleInfo.rodata
while (code[0] != 0xffffffffu)
{
entry = code[0] + 0x81000000;
code++;
}
arm7_thread(entry & ~1 /* TODO: Thumb/ARM encoding selection */, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run();
break;
}
case MACHINE_SPU: spu_thread(m_ehdr.is_le() ? m_ehdr.data_le.e_entry : m_ehdr.data_be.e_entry, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); break; case MACHINE_SPU: spu_thread(m_ehdr.is_le() ? m_ehdr.data_le.e_entry : m_ehdr.data_be.e_entry, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); break;
} }
@ -94,6 +118,8 @@ namespace loader
handler::error_code elf32::load_data(u32 offset) handler::error_code elf32::load_data(u32 offset)
{ {
Elf_Machine machine = (Elf_Machine)(u16)(m_ehdr.is_le() ? m_ehdr.data_le.e_machine : m_ehdr.data_be.e_machine);
for (auto &phdr : m_phdrs) for (auto &phdr : m_phdrs)
{ {
u32 memsz = m_ehdr.is_le() ? phdr.data_le.p_memsz : phdr.data_be.p_memsz; u32 memsz = m_ehdr.is_le() ? phdr.data_le.p_memsz : phdr.data_be.p_memsz;
@ -106,7 +132,7 @@ namespace loader
case 0x00000001: //LOAD case 0x00000001: //LOAD
if (phdr.data_le.p_memsz) if (phdr.data_le.p_memsz)
{ {
if (!vm::alloc(vaddr, memsz, vm::main)) if (machine == MACHINE_ARM && !Memory.PSV.RAM.AllocFixed(vaddr, memsz))
{ {
LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%x) failed", __FUNCTION__, vaddr, memsz); LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%x) failed", __FUNCTION__, vaddr, memsz);

View file

@ -27,7 +27,7 @@ namespace loader
u16 e_type; u16 e_type;
u16 e_machine; u16 e_machine;
u32 e_version; u32 e_version;
u16 e_entry; u32 e_entry;
u32 e_phoff; u32 e_phoff;
u32 e_shoff; u32 e_shoff;
u32 e_flags; u32 e_flags;
@ -45,7 +45,7 @@ namespace loader
be_t<u16> e_type; be_t<u16> e_type;
be_t<u16> e_machine; be_t<u16> e_machine;
be_t<u32> e_version; be_t<u32> e_version;
be_t<u16> e_entry; be_t<u32> e_entry;
be_t<u32> e_phoff; be_t<u32> e_phoff;
be_t<u32> e_shoff; be_t<u32> e_shoff;
be_t<u32> e_flags; be_t<u32> e_flags;
@ -59,7 +59,7 @@ namespace loader
}; };
bool is_le() const { return e_data == 1; } bool is_le() const { return e_data == 1; }
bool check() const { return e_magic == 0x7F454C46; } bool check() const { return e_magic == 0x464C457F; }
}; };
struct shdr struct shdr

View file

@ -350,12 +350,12 @@ namespace loader
ppu_thr_exit_data[0] = ADDI(r11, 0, 41); ppu_thr_exit_data[0] = ADDI(r11, 0, 41);
ppu_thr_exit_data[1] = SC(2); ppu_thr_exit_data[1] = SC(2);
ppu_thr_exit_data[2] = BLR(); ppu_thr_exit_data[2] = BLR();
Emu.SetPPUThreadExit(ppu_thr_exit_data.addr()); Emu.SetCPUThreadExit(ppu_thr_exit_data.addr());
auto ppu_thr_stop_data = vm::ptr<u32>::make(Memory.MainMem.AllocAlign(2 * 4)); auto ppu_thr_stop_data = vm::ptr<u32>::make(Memory.MainMem.AllocAlign(2 * 4));
ppu_thr_stop_data[0] = SC(4); ppu_thr_stop_data[0] = SC(4);
ppu_thr_stop_data[1] = BLR(); ppu_thr_stop_data[1] = BLR();
Emu.SetPPUThreadStop(ppu_thr_stop_data.addr()); Emu.SetCPUThreadStop(ppu_thr_stop_data.addr());
vm::write64(Memory.PRXMem.AllocAlign(0x10000), 0xDEADBEEFABADCAFE); vm::write64(Memory.PRXMem.AllocAlign(0x10000), 0xDEADBEEFABADCAFE);
/* /*