diff --git a/rpcs3/Emu/ARMv7/ARMv7Context.h b/rpcs3/Emu/ARMv7/ARMv7Context.h index f1cd694844..491c00f9d7 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Context.h +++ b/rpcs3/Emu/ARMv7/ARMv7Context.h @@ -110,6 +110,9 @@ struct ARMv7Context } ITSTATE; + u32 R_ADDR; + u64 R_DATA; + void write_gpr(u32 n, u32 value) { assert(n < 16); @@ -135,6 +138,21 @@ struct ARMv7Context return read_pc(); } + + // function for processing va_args in printf-like functions + u32 get_next_gpr_arg(u32& g_count, u32& f_count, u32& v_count) + { + assert(!f_count && !v_count); // not supported + + if (g_count < 4) + { + return GPR[g_count++]; + } + else + { + return get_stack_arg(g_count++); + } + } }; template::value> diff --git a/rpcs3/Emu/ARMv7/ARMv7Decoder.h b/rpcs3/Emu/ARMv7/ARMv7Decoder.h index 8e54b8880e..14a2fc5c83 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Decoder.h +++ b/rpcs3/Emu/ARMv7/ARMv7Decoder.h @@ -22,7 +22,7 @@ public: code.code1 = vm::psv::read16(address + 2 & ~1); u32 arg = address & 0x1 ? code.data : (u32)code.code0 << 16 | code.code1; - LOG_NOTICE(GENERAL, "code0 = 0x%04x, code1 = 0x%04x, data = 0x%08x, arg = 0x%08x", code.code0, code.code1, code.data, arg); + //LOG_NOTICE(GENERAL, "code0 = 0x%04x, code1 = 0x%04x, data = 0x%08x, arg = 0x%08x", code.code0, code.code1, code.data, arg); // old decoding algorithm @@ -32,7 +32,7 @@ public: { code.data = opcode.length == 2 ? code.code0 : arg; (*opcode.func)(m_thr.context, code, opcode.type); - // LOG_NOTICE(GENERAL, "%s, %d \n\n", opcode.name, opcode.length); + //LOG_NOTICE(ARMv7, "%s, %s", opcode.name, m_thr.RegsToString()); return opcode.length; } } diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp index 3fbc1d0ff1..5695e87b9c 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp @@ -1204,12 +1204,12 @@ void ARMv7_instrs::LDR_IMM(ARMv7Context& context, const ARMv7Code code, const AR const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; const u32 addr = index ? offset_addr : context.read_gpr(n); + context.write_gpr(t, vm::psv::read32(addr)); + if (wback) { context.write_gpr(n, offset_addr); } - - context.write_gpr(t, vm::psv::read32(addr)); } } @@ -1224,11 +1224,56 @@ void ARMv7_instrs::LDR_LIT(ARMv7Context& context, const ARMv7Code code, const AR void ARMv7_instrs::LDR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond = context.ITSTATE.advance(); + u32 t = 0; + u32 n = 0; + u32 m = 0; + bool index = true; + bool add = true; + bool wback = false; + auto shift_t = SRType_LSL; + u32 shift_n = 0; + switch (type) { + case T1: + { + t = (code.data & 0x7); + n = (code.data & 0x38) >> 3; + m = (code.data & 0x1c0) >> 6; + break; + } + case T2: + { + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + m = (code.data & 0xf); + shift_n = (code.data & 0x30) >> 4; + + if (n == 15) + { + throw "LDR (literal)"; + } + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (ConditionPassed(context, cond)) + { + const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); + const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset; + const u32 addr = index ? offset_addr : context.read_gpr(n); + const u32 data = vm::psv::read32(addr); + + if (wback) + { + context.write_gpr(n, offset_addr); + } + + context.write_gpr(t, data); + } } @@ -1262,11 +1307,55 @@ void ARMv7_instrs::LDRB_REG(ARMv7Context& context, const ARMv7Code code, const A void ARMv7_instrs::LDRD_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond = context.ITSTATE.advance(); + u32 t = 0; + u32 t2 = 0; + u32 n = 13; + u32 imm32 = 0; + bool index = true; + bool add = true; + bool wback = false; + switch (type) { + case T1: + { + t = (code.data & 0xf000) >> 12; + t2 = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + imm32 = (code.data & 0xff) << 2; + index = (code.data & 0x1000000); + add = (code.data & 0x800000); + wback = (code.data & 0x200000); + + if (!index && !wback) + { + throw "LDRD_IMM_T1: Related encodings"; + } + if (n == 15) + { + throw "LDRD (literal)"; + } + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (ConditionPassed(context, cond)) + { + const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : context.read_gpr(n); + const u64 value = vm::psv::read64(addr); + + context.write_gpr(t, (u32)(value)); + context.write_gpr(t2, (u32)(value >> 32)); + + if (wback) + { + context.write_gpr(n, offset_addr); + } + } } void ARMv7_instrs::LDRD_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -1374,11 +1463,33 @@ void ARMv7_instrs::LDRSH_REG(ARMv7Context& context, const ARMv7Code code, const void ARMv7_instrs::LDREX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond = context.ITSTATE.advance(); + u32 t = 0; + u32 n = 0; + u32 imm32 = 0; + switch (type) { + case T1: + { + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + imm32 = (code.data & 0xff) << 2; + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (ConditionPassed(context, cond)) + { + const u32 addr = context.read_gpr(n) + imm32; + const u32 value = vm::psv::read32(addr); + + context.R_ADDR = addr; + context.R_DATA = value; + context.write_gpr(t, value); + } } void ARMv7_instrs::LDREXB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -1853,14 +1964,17 @@ void ARMv7_instrs::POP(ARMv7Context& context, const ARMv7Code code, const ARMv7_ if (ConditionPassed(context, cond)) { + u32 written = 0; for (u16 mask = 1, i = 0; mask; mask <<= 1, i++) { if (reg_list & mask) { - context.write_gpr(i, vm::psv::read32(context.SP)); - context.SP += 4; + context.write_gpr(i, vm::psv::read32(context.SP + written)); + written += 4; } } + + context.SP += written; } } @@ -1907,14 +2021,17 @@ void ARMv7_instrs::PUSH(ARMv7Context& context, const ARMv7Code code, const ARMv7 if (ConditionPassed(context, cond)) { + u32 read = 0; for (u16 mask = 1 << 15, i = 15; mask; mask >>= 1, i--) { if (reg_list & mask) { - context.SP -= 4; - vm::psv::write32(context.SP, context.read_gpr(i)); + read += 4; + vm::psv::write32(context.SP - read, context.read_gpr(i)); } } + + context.SP -= read; } } @@ -2692,11 +2809,35 @@ void ARMv7_instrs::STRH_REG(ARMv7Context& context, const ARMv7Code code, const A void ARMv7_instrs::STREX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond = context.ITSTATE.advance(); + u32 d = 0; + u32 t = 0; + u32 n = 0; + u32 imm32 = 0; + switch (type) { + case T1: + { + d = (code.data & 0xf00) >> 8; + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + imm32 = (code.data & 0xff) << 2; + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (ConditionPassed(context, cond)) + { + const u32 addr = context.read_gpr(n) + imm32; + const u32 value = context.read_gpr(t); + + auto& sync_obj = vm::get_ref>(addr); + context.write_gpr(d, addr != context.R_ADDR || sync_obj.compare_and_swap((u32)context.R_DATA, value) != context.R_DATA); + context.R_ADDR = 0; + } } void ARMv7_instrs::STREXB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h index 0bf9652ba6..1736fdd38a 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h @@ -500,6 +500,15 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] = ARMv7_OP2(0xff00, 0xbf00, T1, IT), + ARMv7_OP4(0xfff0, 0x0f00, 0xe850, 0x0f00, T1, LDREX), + ARMv7_OP4(0x0ff0, 0x0fff, 0x0190, 0x0f9f, A1, LDREX), + ARMv7_OP4(0xfff0, 0x0fff, 0xe8d0, 0x0f4f, T1, LDREXB), + ARMv7_OP4(0x0ff0, 0x0fff, 0x01d0, 0x0f9f, A1, LDREXB), + ARMv7_OP4(0xfff0, 0x00ff, 0xe8d0, 0x007f, T1, LDREXD), + ARMv7_OP4(0x0ff0, 0x0fff, 0x01b0, 0x0f9f, A1, LDREXD), + ARMv7_OP4(0xfff0, 0x0fff, 0xe8d0, 0x0f5f, T1, LDREXH), + ARMv7_OP4(0x0ff0, 0x0fff, 0x01f0, 0x0f9f, A1, LDREXH), + ARMv7_OP2(0xf800, 0xc800, T1, LDM), ARMv7_OP4(0xffd0, 0x2000, 0xe890, 0x0000, T2, LDM), ARMv7_OP4(0x0fd0, 0x0000, 0x0890, 0x0000, A1, LDM), @@ -554,15 +563,6 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] = ARMv7_OP4(0xfff0, 0x0fc0, 0xf930, 0x0000, T2, LDRSH_REG), ARMv7_OP4(0x0e50, 0x0ff0, 0x0010, 0x00f0, A1, LDRSH_REG), - ARMv7_OP4(0xfff0, 0x0f00, 0xe850, 0x0f00, T1, LDREX), - ARMv7_OP4(0x0ff0, 0x0fff, 0x0190, 0x0f9f, A1, LDREX), - ARMv7_OP4(0xfff0, 0x0fff, 0xe8d0, 0x0f4f, T1, LDREXB), - ARMv7_OP4(0x0ff0, 0x0fff, 0x01d0, 0x0f9f, A1, LDREXB), - ARMv7_OP4(0xfff0, 0x00ff, 0xe8d0, 0x007f, T1, LDREXD), - ARMv7_OP4(0x0ff0, 0x0fff, 0x01b0, 0x0f9f, A1, LDREXD), - ARMv7_OP4(0xfff0, 0x0fff, 0xe8d0, 0x0f5f, T1, LDREXH), - ARMv7_OP4(0x0ff0, 0x0fff, 0x01f0, 0x0f9f, A1, LDREXH), - ARMv7_OP2(0xf800, 0x0000, T1, LSL_IMM), ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0000, T2, LSL_IMM), ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0000, A1, LSL_IMM), @@ -773,6 +773,15 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] = ARMv7_OP4(0xfff0, 0xf0f0, 0xfac0, 0xf000, T1, SSUB8), ARMv7_OP4(0x0ff0, 0x0ff0, 0x0610, 0x0ff0, A1, SSUB8), + ARMv7_OP4(0xfff0, 0x0000, 0xe840, 0x0000, T1, STREX), + ARMv7_OP4(0x0ff0, 0x0ff0, 0x0180, 0x0f90, A1, STREX), + ARMv7_OP4(0xfff0, 0x0ff0, 0xe8c0, 0x0f40, T1, STREXB), + ARMv7_OP4(0x0ff0, 0x0ff0, 0x01c0, 0x0f90, A1, STREXB), + ARMv7_OP4(0xfff0, 0x00f0, 0xe8c0, 0x0070, T1, STREXD), + ARMv7_OP4(0x0ff0, 0x0ff0, 0x01a0, 0x0f90, A1, STREXD), + ARMv7_OP4(0xfff0, 0x0ff0, 0xe8c0, 0x0f50, T1, STREXH), + ARMv7_OP4(0x0ff0, 0x0ff0, 0x01e0, 0x0f90, A1, STREXH), + ARMv7_OP2(0xf800, 0xc000, T1, STM), ARMv7_OP4(0xffd0, 0xa000, 0xe880, 0x0000, T2, STM), ARMv7_OP4(0x0fd0, 0x0000, 0x0880, 0x0000, A1, STM), @@ -810,15 +819,6 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] = ARMv7_OP4(0xfff0, 0x0fc0, 0xf820, 0x0000, T2, STRH_REG), ARMv7_OP4(0x0e50, 0x0ff0, 0x0000, 0x00b0, A1, STRH_REG), - ARMv7_OP4(0xfff0, 0x0000, 0xe840, 0x0000, T1, STREX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0180, 0x0f90, A1, STREX), - ARMv7_OP4(0xfff0, 0x0ff0, 0xe8c0, 0x0f40, T1, STREXB), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x01c0, 0x0f90, A1, STREXB), - ARMv7_OP4(0xfff0, 0x00f0, 0xe8c0, 0x0070, T1, STREXD), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x01a0, 0x0f90, A1, STREXD), - ARMv7_OP4(0xfff0, 0x0ff0, 0xe8c0, 0x0f50, T1, STREXH), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x01e0, 0x0f90, A1, STREXH), - ARMv7_OP2(0xff80, 0xb080, T1, SUB_SPI), ARMv7_OP4(0xfbef, 0x8000, 0xf1ad, 0x0000, T2, SUB_SPI), ARMv7_OP4(0xfbff, 0x8000, 0xf2ad, 0x0000, T3, SUB_SPI), diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index b07f39f522..3fb874ee2c 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -87,7 +87,7 @@ struct SceKernelSystemInfo #pragma pack(pop) -s32 sceKernelCreateThread( +u32 sceKernelCreateThread( vm::psv::ptr pName, vm::psv::ptr entry, s32 initPriority, @@ -101,24 +101,21 @@ s32 sceKernelCreateThread( ARMv7Thread& new_thread = static_cast(Emu.GetCPU().AddThread(CPU_THREAD_ARMv7)); - u32 id = new_thread.GetId(); + const auto id = new_thread.GetId(); new_thread.SetEntry(entry.addr() ^ 1); new_thread.SetPrio(initPriority); new_thread.SetStackSize(stackSize); new_thread.SetName(pName.get_ptr()); - sceLibKernel.Error("*** New ARMv7 Thread [%s] (entry=0x%x)^1: id = %d", pName.get_ptr(), entry, id); + sceLibKernel.Error("*** New ARMv7 Thread [%s] (entry=0x%x)^1: id -> 0x%x", pName.get_ptr(), entry, id); new_thread.Run(); - - Emu.Pause(); - return id; } -s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr pArgBlock) +s32 sceKernelStartThread(u32 threadId, u32 argSize, vm::psv::ptr pArgBlock) { - sceLibKernel.Error("sceKernelStartThread(threadId=%d, argSize=%d, pArgBlock=0x%x)", threadId, argSize, pArgBlock); + sceLibKernel.Error("sceKernelStartThread(threadId=0x%x, argSize=0x%x, pArgBlock=0x%x)", threadId, argSize, pArgBlock); std::shared_ptr t = Emu.GetCPU().GetThread(threadId); @@ -134,8 +131,8 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr pAr memcpy(vm::get_ptr(pos), pArgBlock.get_ptr(), argSize); // set SceKernelThreadEntry function arguments - thread.context.write_gpr(0, argSize); - thread.context.write_gpr(1, pos); + thread.context.GPR[0] = argSize; + thread.context.GPR[1] = pos; thread.Exec(); return SCE_OK; @@ -151,9 +148,9 @@ s32 sceKernelExitThread(ARMv7Context& context, s32 exitStatus) return SCE_OK; } -s32 sceKernelDeleteThread(s32 threadId) +s32 sceKernelDeleteThread(u32 threadId) { - sceLibKernel.Todo("sceKernelDeleteThread(threadId=%d)", threadId); + sceLibKernel.Todo("sceKernelDeleteThread(threadId=0x%x)", threadId); return SCE_OK; } @@ -165,21 +162,21 @@ s32 sceKernelExitDeleteThread(s32 exitStatus) return SCE_OK; } -s32 sceKernelChangeThreadCpuAffinityMask(s32 threadId, s32 cpuAffinityMask) +s32 sceKernelChangeThreadCpuAffinityMask(u32 threadId, s32 cpuAffinityMask) { - sceLibKernel.Todo("sceKernelChangeThreadCpuAffinityMask(threadId=%d, cpuAffinityMask=0x%x)", threadId, cpuAffinityMask); + sceLibKernel.Todo("sceKernelChangeThreadCpuAffinityMask(threadId=0x%x, cpuAffinityMask=0x%x)", threadId, cpuAffinityMask); return SCE_OK; } -s32 sceKernelGetThreadCpuAffinityMask(s32 threadId) +s32 sceKernelGetThreadCpuAffinityMask(u32 threadId) { sceLibKernel.Todo("sceKernelGetThreadCpuAffinityMask(threadId=0x%x)", threadId); return SCE_OK; } -s32 sceKernelChangeThreadPriority(s32 threadId, s32 priority) +s32 sceKernelChangeThreadPriority(u32 threadId, s32 priority) { sceLibKernel.Todo("sceKernelChangeThreadPriority(threadId=0x%x, priority=%d)", threadId, priority); @@ -193,11 +190,11 @@ s32 sceKernelGetThreadCurrentPriority() return SCE_OK; } -s32 sceKernelGetThreadId() +u32 sceKernelGetThreadId(ARMv7Context& context) { - sceLibKernel.Todo("sceKernelGetThreadId()"); + sceLibKernel.Log("sceKernelGetThreadId()"); - return SCE_OK; + return context.thread.GetId(); } s32 sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr) @@ -207,9 +204,9 @@ s32 sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr) return SCE_OK; } -s32 sceKernelGetThreadExitStatus(s32 threadId, vm::psv::ptr pExitStatus) +s32 sceKernelGetThreadExitStatus(u32 threadId, vm::psv::ptr pExitStatus) { - sceLibKernel.Todo("sceKernelGetThreadExitStatus(threadId=%d, pExitStatus=0x%x)", threadId, pExitStatus); + sceLibKernel.Todo("sceKernelGetThreadExitStatus(threadId=0x%x, pExitStatus=0x%x)", threadId, pExitStatus); return SCE_OK; } @@ -228,9 +225,9 @@ s32 sceKernelCheckWaitableStatus() return SCE_OK; } -s32 sceKernelGetThreadInfo(s32 threadId, vm::psv::ptr pInfo) +s32 sceKernelGetThreadInfo(u32 threadId, vm::psv::ptr pInfo) { - sceLibKernel.Todo("sceKernelGetThreadInfo(threadId=%d, pInfo=0x%x)", threadId, pInfo); + sceLibKernel.Todo("sceKernelGetThreadInfo(threadId=0x%x, pInfo=0x%x)", threadId, pInfo); return SCE_OK; } @@ -251,7 +248,7 @@ s32 sceKernelGetSystemInfo(vm::psv::ptr pInfo) s32 sceKernelGetThreadmgrUIDClass(s32 uid) { - sceLibKernel.Todo("sceKernelGetThreadmgrUIDClass(uid=%d)", uid); + sceLibKernel.Todo("sceKernelGetThreadmgrUIDClass(uid=0x%x)", uid); return SCE_OK; } @@ -284,16 +281,44 @@ s32 sceKernelDelayThreadCB(u32 usec) return SCE_OK; } -s32 sceKernelWaitThreadEnd(s32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout) +s32 sceKernelWaitThreadEnd(u32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout) { - sceLibKernel.Todo("sceKernelWaitThreadEnd(threadId=%d, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout); + sceLibKernel.Error("sceKernelWaitThreadEnd(threadId=0x%x, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout); + + std::shared_ptr t = Emu.GetCPU().GetThread(threadId); + + if (!t || t->GetType() != CPU_THREAD_ARMv7) + { + RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID); + } + + ARMv7Thread& thread = static_cast(*t); + + if (pTimeout) + { + } + + while (thread.IsAlive()) + { + if (Emu.IsStopped()) + { + sceLibKernel.Warning("sceKernelWaitThreadEnd(0x%x) aborted", threadId); + return SCE_OK; + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } + + if (pExitStatus) + { + *pExitStatus = thread.context.GPR[0]; + } return SCE_OK; } -s32 sceKernelWaitThreadEndCB(s32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout) +s32 sceKernelWaitThreadEndCB(u32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout) { - sceLibKernel.Todo("sceKernelWaitThreadEndCB(threadId=%d, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout); + sceLibKernel.Todo("sceKernelWaitThreadEndCB(threadId=0x%x, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout); return SCE_OK; } diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index 9abcf593e4..5c5e7599f8 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -26,11 +26,67 @@ namespace sce_libc_func }); } - void printf(vm::psv::ptr fmt) // va_args... + void printf(ARMv7Context& context, vm::psv::ptr fmt) // va_args... { sceLibc.Error("printf(fmt=0x%x)", fmt); - LOG_NOTICE(TTY, "%s", fmt.get_ptr()); + sceLibc.Notice("*** *fmt = '%s'", fmt.get_ptr()); + + std::string result; + u32 g_count = 1; + u32 f_count = 0; + u32 v_count = 0; + + for (char c = *fmt++; c; c = *fmt++) + { + switch (c) + { + case '%': + { + const auto start = fmt - 1; + const bool = *fmt == '#' ? fmt++, true : false; + + switch (*fmt++) + { + case '%': + { + result += '%'; + continue; + } + case 'd': + case 'i': + { + // signed decimal + const s64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + + result += fmt::to_sdec(value); + continue; + } + case 'x': + { + // hexadecimal + const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + + if ( && value) + { + result += "0x"; + } + + result += fmt::to_hex(value); + continue; + } + default: + { + throw fmt::Format("printf(): unknown formatting: '%s'", start.get_ptr()); + } + } + } + } + + result += c; + } + + LOG_NOTICE(TTY, result); } void __cxa_set_dso_handle_main()