Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Common/Data/Random/Rng.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ class GMRng {
uint32_t m_z;
};


// Data must consist only of the index and the twister array. This matches the PSP
// MT context exactly.
class MersenneTwister {
Expand Down
1 change: 1 addition & 0 deletions Common/Log.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ enum class Log {
sceSas,
sceUtility,
sceMisc,
sceReg,

NUMBER_OF_LOGS, // Must be last
};
Expand Down
1 change: 1 addition & 0 deletions Common/Log/LogManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ static const char * const g_logTypeNames[] = {
"SCESAS",
"SCEUTIL",
"SCEMISC",
"SCEREG",
};

const char *LogManager::GetLogTypeName(Log type) {
Expand Down
9 changes: 9 additions & 0 deletions Core/HLE/ErrorCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -503,4 +503,13 @@ enum PSPErrorCode : u32 {
SCE_REG_ERROR_CATEGORY_NOT_FOUND = 0x80082718,
SCE_REG_ERROR_INVALID_NAME = 0x80082738,
SCE_REG_ERROR_PERMISSION_FAILURE = 0x8008273b,

SCE_MP3_ERROR_INVALID_HANDLE = 0x80671001,
SCE_MP3_ERROR_UNRESERVED_HANDLE = 0x80671102,
SCE_MP3_ERROR_NOT_YET_INIT_HANDLE = 0x80671103,
SCE_MP3_ERROR_NO_RESOURCE_AVAIL = 0x80671201,
SCE_MP3_ERROR_BAD_SAMPLE_RATE = 0x80671302,
SCE_MP3_ERROR_BAD_RESET_FRAME = 0x80671501,
SCE_MP3_ERROR_BAD_ADDR = 0x80671002,
SCE_MP3_ERROR_BAD_SIZE = 0x80671003,
};
28 changes: 16 additions & 12 deletions Core/HLE/sceAudiocodec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,10 @@ static int __AudioCodecInitCommon(u32 ctxPtr, int codec, bool mono) {
}

// Create audio decoder for given audio codec and push it into AudioList
if (inFrameBytes) {
INFO_LOG(Log::ME, "sceAudioDecoder: Creating codec with %04x frame size and %d channels, codec %04x", inFrameBytes, channels, codec);
AudioDecoder *decoder = CreateAudioDecoder(audioType, 44100, channels, inFrameBytes);
decoder->SetCtxPtr(ctxPtr);
g_audioDecoderContexts[ctxPtr] = decoder;
} else {
ERROR_LOG(Log::ME, "sceAudioDecoder: Unsupported codec %08x", codec);
g_audioDecoderContexts[ctxPtr] = nullptr;
}
INFO_LOG(Log::ME, "sceAudioDecoder: Creating codec with %04x frame size and %d channels, codec %04x", inFrameBytes, channels, codec);
AudioDecoder *decoder = CreateAudioDecoder(audioType, 44100, channels, inFrameBytes);
decoder->SetCtxPtr(ctxPtr);
g_audioDecoderContexts[ctxPtr] = decoder;
return hleLogDebug(Log::ME, 0);
}

Expand All @@ -178,9 +173,18 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) {
// TODO: Should check that codec corresponds to the currently used codec in the context, I guess..

auto ctx = PSPPointer<SceAudiocodecCodec>::Create(ctxPtr); // On game-owned heap, no need to allocate.
int inFrameBytes;
int channels;
CalculateInputBytesAndChannelsAt3Plus(ctx, &inFrameBytes, &channels);

int inFrameBytes = 0;
int channels = 2;

switch (codec) {
case PSP_CODEC_AT3PLUS:
CalculateInputBytesAndChannelsAt3Plus(ctx, &inFrameBytes, &channels);
break;
case PSP_CODEC_MP3:
inFrameBytes = ctx->srcBytesRead;
break;
}

// find a decoder in audioList
auto decoder = findDecoder(ctxPtr);
Expand Down
24 changes: 8 additions & 16 deletions Core/HLE/sceGameUpdate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,20 @@
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HLE/sceGameUpdate.h"

static u32 sceGameUpdateInit()
{
ERROR_LOG(Log::sceUtility, "UNIMPL sceGameUpdateInit()");
return 0;
static u32 sceGameUpdateInit() {
return hleLogError(Log::sceUtility, 0, "UNIMPL");
}

static u32 sceGameUpdateTerm()
{
ERROR_LOG(Log::sceUtility, "UNIMPL sceGameUpdateTerm()");
return 0;
static u32 sceGameUpdateTerm() {
return hleLogError(Log::sceUtility, 0, "UNIMPL");
}

static u32 sceGameUpdateRun()
{
ERROR_LOG(Log::sceUtility, "UNIMPL sceGameUpdateRun()");
return 0;
static u32 sceGameUpdateRun() {
return hleLogError(Log::sceUtility, 0, "UNIMPL");
}

static u32 sceGameUpdateAbort()
{
ERROR_LOG(Log::sceUtility, "UNIMPL sceGameUpdateAbort()");
return 0;
static u32 sceGameUpdateAbort() {
return hleLogError(Log::sceUtility, 0, "UNIMPL");
}

const HLEFunction sceGameUpdate[] =
Expand Down
64 changes: 24 additions & 40 deletions Core/HLE/sceHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,119 +83,107 @@ void __HeapShutdown() {

static int sceHeapReallocHeapMemory(u32 heapAddr, u32 memPtr, int memSize) {
ERROR_LOG_REPORT(Log::HLE,"UNIMPL sceHeapReallocHeapMemory(%08x, %08x, %08x)", heapAddr, memPtr, memSize);
return 0;
return hleNoLog(0);
}

static int sceHeapReallocHeapMemoryWithOption(u32 heapPtr, u32 memPtr, int memSize, u32 paramsPtr) {
ERROR_LOG_REPORT(Log::HLE,"UNIMPL sceHeapReallocHeapMemoryWithOption(%08x, %08x, %08x, %08x)", heapPtr, memPtr, memSize, paramsPtr);
return 0;
return hleNoLog(0);
}

static int sceHeapFreeHeapMemory(u32 heapAddr, u32 memAddr) {
Heap *heap = getHeap(heapAddr);
if (!heap) {
ERROR_LOG(Log::HLE, "sceHeapFreeHeapMemory(%08x, %08x): invalid heap", heapAddr, memAddr);
return SCE_KERNEL_ERROR_INVALID_ID;
return hleLogError(Log::HLE, SCE_KERNEL_ERROR_INVALID_ID, "invalid heap");
}

DEBUG_LOG(Log::HLE, "sceHeapFreeHeapMemory(%08x, %08x)", heapAddr, memAddr);
// An invalid address will crash the PSP, but 0 is always returns success.
if (memAddr == 0) {
return 0;
return hleLogDebug(Log::HLE, 0);
}

if (!heap->alloc.FreeExact(memAddr)) {
return SCE_KERNEL_ERROR_INVALID_POINTER;
return hleLogError(Log::HLE, SCE_KERNEL_ERROR_INVALID_POINTER);
}
return 0;
return hleLogDebug(Log::HLE, 0);
}

static int sceHeapGetMallinfo(u32 heapAddr, u32 infoPtr) {
ERROR_LOG_REPORT(Log::HLE,"UNIMPL sceHeapGetMallinfo(%08x, %08x)", heapAddr, infoPtr);
return 0;
return hleNoLog(0);
}

static u32 sceHeapAllocHeapMemoryWithOption(u32 heapAddr, u32 memSize, u32 paramsPtr) {
Heap *heap = getHeap(heapAddr);
u32 grain = 4;
if (!heap) {
ERROR_LOG(Log::HLE, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid heap", heapAddr, memSize, paramsPtr);
return 0;
return hleLogError(Log::HLE, 0, "invalid heap");
}

u32 grain = 4;
// 0 is ignored.
if (paramsPtr != 0) {
u32 size = Memory::Read_U32(paramsPtr);
if (size < 8) {
ERROR_LOG(Log::HLE, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid param size", heapAddr, memSize, paramsPtr);
return 0;
return hleLogError(Log::HLE, 0, "invalid param size");
}
if (size > 8) {
WARN_LOG_REPORT(Log::HLE, "sceHeapAllocHeapMemoryWithOption(): unexpected param size %d", size);
}
grain = Memory::Read_U32(paramsPtr + 4);
}

DEBUG_LOG(Log::HLE,"sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x)", heapAddr, memSize, paramsPtr);
// There's 8 bytes at the end of every block, reserved.
memSize += 8;
u32 addr = heap->alloc.AllocAligned(memSize, grain, grain, true);
return addr;
return hleLogDebug(Log::HLE, addr);
}

static int sceHeapGetTotalFreeSize(u32 heapAddr) {
Heap *heap = getHeap(heapAddr);
if (!heap) {
ERROR_LOG(Log::HLE, "sceHeapGetTotalFreeSize(%08x): invalid heap", heapAddr);
return SCE_KERNEL_ERROR_INVALID_ID;
return hleLogError(Log::HLE, SCE_KERNEL_ERROR_INVALID_ID, "invalid heap");
}

DEBUG_LOG(Log::HLE, "sceHeapGetTotalFreeSize(%08x)", heapAddr);
u32 free = heap->alloc.GetTotalFreeBytes();
if (free >= 8) {
// Every allocation requires an extra 8 bytes.
free -= 8;
}
return free;
return hleLogDebug(Log::HLE, free);
}

static int sceHeapIsAllocatedHeapMemory(u32 heapPtr, u32 memPtr) {
if (!Memory::IsValidAddress(memPtr)) {
ERROR_LOG(Log::HLE, "sceHeapIsAllocatedHeapMemory(%08x, %08x): invalid address", heapPtr, memPtr);
return SCE_KERNEL_ERROR_INVALID_POINTER;
return hleLogError(Log::HLE, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid address");
}

DEBUG_LOG(Log::HLE, "sceHeapIsAllocatedHeapMemory(%08x, %08x)", heapPtr, memPtr);
Heap *heap = getHeap(heapPtr);
// An invalid heap is fine, it's not a member of this heap one way or another.
// Only an exact address matches. Off by one crashes, and off by 4 says no.
if (heap && heap->alloc.GetBlockStartFromAddress(memPtr) == memPtr) {
return 1;
return hleLogDebug(Log::HLE, 1);
}
return 0;
return hleLogDebug(Log::HLE, 0);
}

static int sceHeapDeleteHeap(u32 heapAddr) {
Heap *heap = getHeap(heapAddr);
if (!heap) {
ERROR_LOG(Log::HLE, "sceHeapDeleteHeap(%08x): invalid heap", heapAddr);
return SCE_KERNEL_ERROR_INVALID_ID;
return hleLogError(Log::HLE, SCE_KERNEL_ERROR_INVALID_ID, "invalid heap");
}

DEBUG_LOG(Log::HLE, "sceHeapDeleteHeap(%08x)", heapAddr);
heapList.erase(heapAddr);
delete heap;
return 0;
return hleLogDebug(Log::HLE, 0);
}

static int sceHeapCreateHeap(const char* name, u32 heapSize, int attr, u32 paramsPtr) {
if (paramsPtr != 0) {
u32 size = Memory::Read_U32(paramsPtr);
WARN_LOG_REPORT(Log::HLE, "sceHeapCreateHeap(): unsupported options parameter, size = %d", size);
}
if (name == NULL) {
if (!name) {
WARN_LOG_REPORT(Log::HLE, "sceHeapCreateHeap(): name is NULL");
return 0;
return hleNoLog(0);
}
int allocSize = (heapSize + 3) & ~3;

Expand All @@ -204,33 +192,29 @@ static int sceHeapCreateHeap(const char* name, u32 heapSize, int attr, u32 param
heap->fromtop = (attr & PSP_HEAP_ATTR_HIGHMEM) != 0;
u32 addr = userMemory.Alloc(heap->size, heap->fromtop, StringFromFormat("Heap/%s", name).c_str());
if (addr == (u32)-1) {
ERROR_LOG(Log::HLE, "sceHeapCreateHeap(): Failed to allocate %i bytes memory", allocSize);
delete heap;
return 0;
return hleLogError(Log::HLE, 0, "Failed to allocate %i bytes memory", allocSize);
}
heap->address = addr;

// Some of the heap is reserved by the implementation (the first 128 bytes, and 8 after each block.)
heap->alloc.Init(heap->address + 128, heap->size - 128, true);
heapList[heap->address] = heap;
DEBUG_LOG(Log::HLE, "%08x=sceHeapCreateHeap(%s, %08x, %08x, %08x)", heap->address, name, heapSize, attr, paramsPtr);
return heap->address;
return hleLogDebug(Log::HLE, heap->address);
}

static u32 sceHeapAllocHeapMemory(u32 heapAddr, u32 memSize) {
Heap *heap = getHeap(heapAddr);
if (!heap) {
ERROR_LOG(Log::HLE, "sceHeapAllocHeapMemory(%08x, %08x): invalid heap", heapAddr, memSize);
// Yes, not 0 (returns a pointer), but an error code. Strange.
return SCE_KERNEL_ERROR_INVALID_ID;
return hleLogError(Log::HLE, SCE_KERNEL_ERROR_INVALID_ID, "invalid heap");
}

DEBUG_LOG(Log::HLE, "sceHeapAllocHeapMemory(%08x, %08x)", heapAddr, memSize);
// There's 8 bytes at the end of every block, reserved.
memSize += 8;
// Always goes down, regardless of whether the heap is high or low.
u32 addr = heap->alloc.Alloc(memSize, true);
return addr;
return hleLogDebug(Log::HLE, addr);
}


Expand Down
9 changes: 9 additions & 0 deletions Core/HLE/sceKernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1503,6 +1503,15 @@ const char *KernelErrorToString(u32 err) {
case SCE_REG_ERROR_INVALID_NAME: return "SCE_REG_ERROR_INVALID_NAME";
case SCE_REG_ERROR_PERMISSION_FAILURE: return "SCE_REG_ERROR_PERMISSION_FAILURE";

case SCE_MP3_ERROR_INVALID_HANDLE: return "SCE_MP3_ERROR_INVALID_HANDLE";
case SCE_MP3_ERROR_UNRESERVED_HANDLE: return "SCE_MP3_ERROR_UNRESERVED_HANDLE";
case SCE_MP3_ERROR_NOT_YET_INIT_HANDLE: return "SCE_MP3_ERROR_NOT_YET_INIT_HANDLE";
case SCE_MP3_ERROR_NO_RESOURCE_AVAIL: return "SCE_MP3_ERROR_NO_RESOURCE_AVAIL";
case SCE_MP3_ERROR_BAD_SAMPLE_RATE: return "SCE_MP3_ERROR_BAD_SAMPLE_RATE";
case SCE_MP3_ERROR_BAD_RESET_FRAME: return "SCE_MP3_ERROR_BAD_RESET_FRAME";
case SCE_MP3_ERROR_BAD_ADDR: return "SCE_MP3_ERROR_BAD_ADDR";
case SCE_MP3_ERROR_BAD_SIZE: return "SCE_MP3_ERROR_BAD_SIZE";

default:
return nullptr;
}
Expand Down
4 changes: 0 additions & 4 deletions Core/HLE/sceKernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,6 @@ class KernelObjectPool {
template <class T>
T* Get(SceUID handle, u32 &outError) {
if (handle < handleOffset || handle >= handleOffset+maxCount || !occupied[handle-handleOffset]) {
// Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP
if (handle != 0 && (u32)handle != 0x80020001) {
WARN_LOG(Log::sceKernel, "Kernel: Bad %s handle %d (%08x)", T::GetStaticTypeName(), handle, handle);
}
outError = T::GetMissingErrorCode();
return nullptr;
} else {
Expand Down
35 changes: 23 additions & 12 deletions Core/HLE/sceKernelMutex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,25 +523,30 @@ int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr)
// int sceKernelLockMutex(SceUID id, int count, int *timeout)
int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr)
{
// Tekken 6 hack: Let's avoid the unnecessary logspam. It does this on hardware too.
// This ID is always invalid.
if (id == 0x80020001 && timeoutPtr == 0) {
return hleNoLog(0);
}

u32 error;
PSPMutex *mutex = kernelObjects.Get<PSPMutex>(id, error);

if (__KernelLockMutex(mutex, count, error))
return hleLogDebug(Log::sceKernel, 0);
else if (error)
else if (error) {
return hleLogError(Log::sceKernel, error);
else
{
SceUID threadID = __KernelGetCurThread();
// May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates.
if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end())
mutex->waitingThreads.push_back(threadID);
__KernelWaitMutex(mutex, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, false, "mutex waited");

// Return value will be overwritten by wait.
return hleLogDebug(Log::sceKernel, 0);
}

SceUID threadID = __KernelGetCurThread();
// May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates.
if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end())
mutex->waitingThreads.push_back(threadID);
__KernelWaitMutex(mutex, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, false, "mutex waited");

// Return value will be overwritten by wait.
return hleLogDebug(Log::sceKernel, 0);
}

// int sceKernelLockMutexCB(SceUID id, int count, int *timeout)
Expand Down Expand Up @@ -598,6 +603,12 @@ int sceKernelTryLockMutex(SceUID id, int count) {
// int sceKernelUnlockMutex(SceUID id, int count)
int sceKernelUnlockMutex(SceUID id, int count)
{
// Tekken 6 hack: Let's avoid the unnecessary logspam. It does this on hardware too.
// This ID is always invalid.
if (id == 0x80020001) {
return hleNoLog(0);
}

u32 error;
PSPMutex *mutex = kernelObjects.Get<PSPMutex>(id, error);

Expand Down
7 changes: 5 additions & 2 deletions Core/HLE/sceKernelSemaphore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,13 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
}

int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr) {
if (!name)
if (!name) {
// This is strangely quite common! Some shared library must be doing this.
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ERROR, "invalid name");
if (attr >= 0x200)
}
if (attr >= 0x200) {
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter %08x", attr);
}

PSPSemaphore *s = new PSPSemaphore();
SceUID id = kernelObjects.Create(s);
Expand Down
Loading
Loading