Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Xele02 2012-12-16 03:41:13 +01:00
commit a5431f127a
21 changed files with 742 additions and 158 deletions

View File

@ -609,6 +609,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/Dialog/PSPDialog.h
Core/Dialog/PSPMsgDialog.cpp
Core/Dialog/PSPMsgDialog.h
Core/Dialog/PSPOskDialog.cpp
Core/Dialog/PSPOskDialog.h
Core/Dialog/PSPPlaceholderDialog.cpp
Core/Dialog/PSPPlaceholderDialog.h
Core/Dialog/PSPSaveDialog.cpp

View File

@ -1,6 +1,12 @@
set(SRCS
Debugger/Breakpoints.cpp
Debugger/SymbolMap.cpp
Dialog/PSPDialog.cpp
Dialog/PSPMsgDialog.cpp
Dialog/PSPPlaceholderDialog.cpp
Dialog/PSPSaveDialog.cpp
Dialog/SavedataParam.cpp
Dialog/PSPOskDialog.cpp
MIPS/MIPS.cpp
MIPS/MIPSAnalyst.cpp
MIPS/MIPSCodeUtils.cpp

View File

@ -121,6 +121,7 @@
<ClCompile Include="Debugger\SymbolMap.cpp" />
<ClCompile Include="Dialog\PSPDialog.cpp" />
<ClCompile Include="Dialog\PSPMsgDialog.cpp" />
<ClCompile Include="Dialog\PSPOskDialog.cpp" />
<ClCompile Include="Dialog\PSPPlaceholderDialog.cpp" />
<ClCompile Include="Dialog\PSPSaveDialog.cpp" />
<ClCompile Include="Dialog\SavedataParam.cpp" />
@ -263,6 +264,7 @@
<ClInclude Include="Debugger\SymbolMap.h" />
<ClInclude Include="Dialog\PSPDialog.h" />
<ClInclude Include="Dialog\PSPMsgDialog.h" />
<ClInclude Include="Dialog\PSPOskDialog.h" />
<ClInclude Include="Dialog\PSPPlaceholderDialog.h" />
<ClInclude Include="Dialog\PSPSaveDialog.h" />
<ClInclude Include="Dialog\SavedataParam.h" />

View File

@ -339,6 +339,9 @@
<ClCompile Include="Dialog\SavedataParam.cpp">
<Filter>Dialog</Filter>
</ClCompile>
<ClCompile Include="Dialog\PSPOskDialog.cpp">
<Filter>Dialog</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@ -623,6 +626,9 @@
<ClInclude Include="Dialog\SavedataParam.h">
<Filter>Dialog</Filter>
</ClInclude>
<ClInclude Include="Dialog\PSPOskDialog.h">
<Filter>Dialog</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />

View File

@ -48,6 +48,11 @@ void PSPDialog::EndDraw()
PPGeEnd();
}
void PSPDialog::DisplayMessage(std::string text)
{
PPGeDrawText(text.c_str(), 480/2, 100, PPGE_ALIGN_CENTER, 0.5f, 0xFFFFFFFF);
}
void PSPDialog::Shutdown()
{
status = SCE_UTILITY_STATUS_SHUTDOWN;

View File

@ -24,6 +24,20 @@
#define SCE_UTILITY_DIALOG_RESULT_CANCEL 1
#define SCE_UTILITY_DIALOG_RESULT_ABORT 2
typedef struct
{
unsigned int size; /** Size of the structure */
int language; /** Language */
int buttonSwap; /** Set to 1 for X/O button swap */
int graphicsThread; /** Graphics thread priority */
int accessThread; /** Access/fileio thread priority (SceJobThread) */
int fontThread; /** Font thread priority (ScePafThread) */
int soundThread; /** Sound thread priority */
int result; /** Result */
int reserved[4]; /** Set to 0 */
} pspUtilityDialogCommon;
class PSPDialog
{
@ -49,7 +63,7 @@ public:
void EndDraw();
protected:
bool IsButtonPressed(int checkButton);
void DisplayMessage(std::string text);
DialogStatus status;
unsigned int lastButtons;

View File

@ -60,16 +60,12 @@ void PSPMsgDialog::Init(unsigned int paramAddr)
}
void PSPMsgDialog::DisplayMessage(std::string text)
{
PPGeDrawText(text.c_str(), 480/2, 100, PPGE_ALIGN_CENTER, 0.5f, 0xFFFFFFFF);
}
void PSPMsgDialog::DisplayBack()
{
PPGeDrawImage(cancelButtonImg, 250, 220, 20, 20, 0, 0xFFFFFFFF);
PPGeDrawText("Back", 270, 220, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
}
void PSPMsgDialog::DisplayYesNo()
{
@ -87,7 +83,6 @@ void PSPMsgDialog::DisplayYesNo()
}
void PSPMsgDialog::DisplayEnterBack()
{
PPGeDrawImage(okButtonImg, 200, 220, 20, 20, 0, 0xFFFFFFFF);
PPGeDrawText("Enter", 230, 220, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
PPGeDrawImage(cancelButtonImg, 290, 220, 20, 20, 0, 0xFFFFFFFF);
@ -107,7 +102,6 @@ void PSPMsgDialog::Update()
return;
}
const char *text;
if (messageDialog.type == 0) {
char temp[256];

View File

@ -24,20 +24,6 @@
#define SCE_UTILITY_MSGDIALOG_OPTION_YESNO 0x00000010
#define SCE_UTILITY_MSGDIALOG_OPTION_DEFAULT_NO 0x00000100
typedef struct
{
unsigned int size; /** Size of the structure */
int language; /** Language */
int buttonSwap; /** Set to 1 for X/O button swap */
int graphicsThread; /** Graphics thread priority */
int accessThread; /** Access/fileio thread priority (SceJobThread) */
int fontThread; /** Font thread priority (ScePafThread) */
int soundThread; /** Sound thread priority */
int result; /** Result */
int reserved[4]; /** Set to 0 */
} pspUtilityDialogCommon;
struct pspMessageDialog
{
pspUtilityDialogCommon common;
@ -60,7 +46,6 @@ public:
void Shutdown();
private :
void DisplayMessage(std::string text);
void DisplayBack();
void DisplayYesNo();
void DisplayEnterBack();

View File

@ -0,0 +1,238 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "PSPOskDialog.h"
#include "../Util/PPGeDraw.h"
#include "../HLE/sceCtrl.h"
/**
* Enumeration for input language
*/
enum SceUtilityOskInputLanguage
{
PSP_UTILITY_OSK_LANGUAGE_DEFAULT = 0x00,
PSP_UTILITY_OSK_LANGUAGE_JAPANESE = 0x01,
PSP_UTILITY_OSK_LANGUAGE_ENGLISH = 0x02,
PSP_UTILITY_OSK_LANGUAGE_FRENCH = 0x03,
PSP_UTILITY_OSK_LANGUAGE_SPANISH = 0x04,
PSP_UTILITY_OSK_LANGUAGE_GERMAN = 0x05,
PSP_UTILITY_OSK_LANGUAGE_ITALIAN = 0x06,
PSP_UTILITY_OSK_LANGUAGE_DUTCH = 0x07,
PSP_UTILITY_OSK_LANGUAGE_PORTUGESE = 0x08,
PSP_UTILITY_OSK_LANGUAGE_RUSSIAN = 0x09,
PSP_UTILITY_OSK_LANGUAGE_KOREAN = 0x0a
};
/**
* Enumeration for OSK internal state
*/
enum SceUtilityOskState
{
PSP_UTILITY_OSK_DIALOG_NONE = 0, /**< No OSK is currently active */
PSP_UTILITY_OSK_DIALOG_INITING, /**< The OSK is currently being initialized */
PSP_UTILITY_OSK_DIALOG_INITED, /**< The OSK is initialised */
PSP_UTILITY_OSK_DIALOG_VISIBLE, /**< The OSK is visible and ready for use */
PSP_UTILITY_OSK_DIALOG_QUIT, /**< The OSK has been cancelled and should be shut down */
PSP_UTILITY_OSK_DIALOG_FINISHED /**< The OSK has successfully shut down */
};
/**
* Enumeration for OSK field results
*/
enum SceUtilityOskResult
{
PSP_UTILITY_OSK_RESULT_UNCHANGED = 0,
PSP_UTILITY_OSK_RESULT_CANCELLED,
PSP_UTILITY_OSK_RESULT_CHANGED
};
/**
* Enumeration for input types (these are limited by initial choice of language)
*/
enum SceUtilityOskInputType
{
PSP_UTILITY_OSK_INPUTTYPE_ALL = 0x00000000,
PSP_UTILITY_OSK_INPUTTYPE_LATIN_DIGIT = 0x00000001,
PSP_UTILITY_OSK_INPUTTYPE_LATIN_SYMBOL = 0x00000002,
PSP_UTILITY_OSK_INPUTTYPE_LATIN_LOWERCASE = 0x00000004,
PSP_UTILITY_OSK_INPUTTYPE_LATIN_UPPERCASE = 0x00000008,
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_DIGIT = 0x00000100,
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_SYMBOL = 0x00000200,
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_LOWERCASE = 0x00000400,
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_UPPERCASE = 0x00000800,
// http://en.wikipedia.org/wiki/Hiragana
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_HIRAGANA = 0x00001000,
// http://en.wikipedia.org/wiki/Katakana
// Half-width Katakana
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_HALF_KATAKANA = 0x00002000,
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_KATAKANA = 0x00004000,
// http://en.wikipedia.org/wiki/Kanji
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_KANJI = 0x00008000,
PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_LOWERCASE = 0x00010000,
PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_UPPERCASE = 0x00020000,
PSP_UTILITY_OSK_INPUTTYPE_KOREAN = 0x00040000,
PSP_UTILITY_OSK_INPUTTYPE_URL = 0x00080000
};
/**
* OSK Field data
*/
typedef struct _SceUtilityOskData
{
/** Unknown. Pass 0. */
int unk_00;
/** Unknown. Pass 0. */
int unk_04;
/** One of ::SceUtilityOskInputLanguage */
int language;
/** Unknown. Pass 0. */
int unk_12;
/** One or more of ::SceUtilityOskInputType (types that are selectable by pressing SELECT) */
int inputtype;
/** Number of lines */
int lines;
/** Unknown. Pass 0. */
int unk_24;
/** Description text */
u32 descPtr;
/** Initial text */
u32 intextPtr;
/** Length of output text */
int outtextlength;
/** Pointer to the output text */
u32 outtextPtr;
/** Result. One of ::SceUtilityOskResult */
int result;
/** The max text that can be input */
int outtextlimit;
} SceUtilityOskData;
/**
* OSK parameters
*/
typedef struct _SceUtilityOskParams
{
pspUtilityDialogCommon base;
int datacount; /** Number of input fields */
u32 SceUtilityOskDataPtr; /** Pointer to the start of the data for the input fields */
int state; /** The local OSK state, one of ::SceUtilityOskState */
int unk_60;/** Unknown. Pass 0 */
} SceUtilityOskParams;
SceUtilityOskParams oskParams;
SceUtilityOskData oskData;
std::string oskDesc;
std::string oskIntext;
std::string oskOuttext;
int oskParamsAddr;
PSPOskDialog::PSPOskDialog() : PSPDialog() {
}
PSPOskDialog::~PSPOskDialog() {
}
// Same as get string but read out 16bit
void PSPOskDialog::HackyGetStringWide(std::string& _string, const u32 em_address)
{
char stringBuffer[2048];
char *string = stringBuffer;
char c;
u32 addr = em_address;
while ((c = (Memory::Read_U16(addr))))
{
*string++ = c;
addr+=2;
}
*string++ = '\0';
_string = stringBuffer;
}
int PSPOskDialog::Init(u32 oskPtr)
{
status = SCE_UTILITY_STATUS_INITIALIZE;
memset(&oskParams, 0, sizeof(oskParams));
memset(&oskData, 0, sizeof(oskData));
oskParamsAddr = oskPtr;
if (Memory::IsValidAddress(oskPtr))
{
Memory::ReadStruct(oskPtr, &oskParams);
Memory::ReadStruct(oskParams.SceUtilityOskDataPtr, &oskData);
HackyGetStringWide(oskDesc, oskData.descPtr);
HackyGetStringWide(oskIntext, oskData.intextPtr);
HackyGetStringWide(oskOuttext, oskData.outtextPtr);
Memory::WriteStruct(oskParams.SceUtilityOskDataPtr, &oskData);
Memory::WriteStruct(oskPtr, &oskParams);
}
else
{
return -1;
}
return 0;
}
void PSPOskDialog::Update()
{
buttons = __CtrlPeekButtons();
//__UtilityUpdate();
if (status == SCE_UTILITY_STATUS_INITIALIZE)
{
status = SCE_UTILITY_STATUS_RUNNING;
}
else if (status == SCE_UTILITY_STATUS_RUNNING)
{
StartDraw();
DisplayMessage(oskDesc);
PPGeDrawImage(I_CROSS, 200, 220, 20, 20, 0, 0xFFFFFFFF);
PPGeDrawText("Ignore", 230, 220, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
// TODO : Dialogs should take control over input and not send them to the game while displaying
if (IsButtonPressed(CTRL_CROSS))
{
status = SCE_UTILITY_STATUS_FINISHED;
}
EndDraw();
}
else if (status == SCE_UTILITY_STATUS_FINISHED)
{
status = SCE_UTILITY_STATUS_SHUTDOWN;
}
// just fake the return values to be "000000" as this will work for most cases e.g. when restricted to entering just numbers
Memory::Write_U16(0x0030,oskData.outtextPtr);
Memory::Write_U16(0x0030,oskData.outtextPtr+2);
Memory::Write_U16(0x0030,oskData.outtextPtr+4);
Memory::Write_U16(0x0030,oskData.outtextPtr+6);
Memory::Write_U16(0x0030,oskData.outtextPtr+8);
Memory::Write_U16(0x0030,oskData.outtextPtr+10);
Memory::Write_U16(0x0030,oskData.outtextPtr+12);
oskData.outtextlength = 6;
oskParams.base.result= 0;
oskData.result = SceUtilityOskResult::PSP_UTILITY_OSK_RESULT_CHANGED;
Memory::WriteStruct(oskParams.SceUtilityOskDataPtr, &oskData);
Memory::WriteStruct(oskParamsAddr, &oskParams);
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "PSPDialog.h"
#include "../Core/MemMap.h"
class PSPOskDialog: public PSPDialog {
public:
PSPOskDialog();
virtual ~PSPOskDialog();
virtual int Init(u32 oskPtr);
virtual void Update();
private:
void HackyGetStringWide(std::string& _string, const u32 em_address);
};

View File

@ -326,10 +326,10 @@ const HLEFunction ThreadManForUser[] =
{0x812346E4,&WrapU_IU<sceKernelClearEventFlag>, "sceKernelClearEventFlag"},
{0xEF9E4C70,&WrapU_I<sceKernelDeleteEventFlag>, "sceKernelDeleteEventFlag"},
{0x1fb15a32,&WrapU_IU<sceKernelSetEventFlag>, "sceKernelSetEventFlag"},
{0x402FCF22,&WrapV_IUUUU<sceKernelWaitEventFlag>, "sceKernelWaitEventFlag"},
{0x328C546A,&WrapV_IUUUU<sceKernelWaitEventFlagCB>, "sceKernelWaitEventFlagCB"},
{0x402FCF22,&WrapI_IUUUU<sceKernelWaitEventFlag>, "sceKernelWaitEventFlag"},
{0x328C546A,&WrapI_IUUUU<sceKernelWaitEventFlagCB>, "sceKernelWaitEventFlagCB"},
{0x30FD48F0,&WrapI_IUUUU<sceKernelPollEventFlag>, "sceKernelPollEventFlag"},
{0xCD203292,&WrapU_V<sceKernelCancelEventFlag>, "sceKernelCancelEventFlag"},
{0xCD203292,&WrapU_IUU<sceKernelCancelEventFlag>, "sceKernelCancelEventFlag"},
{0xA66B0120,&WrapU_IU<sceKernelReferEventFlagStatus>, "sceKernelReferEventFlagStatus"},
{0x8FFDF9A2,&WrapI_IIU<sceKernelCancelSema>, "sceKernelCancelSema"},

View File

@ -19,13 +19,13 @@
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../../Core/CoreTiming.h"
#include "sceKernel.h"
#include "sceKernelThread.h"
#include "sceKernelEventFlag.h"
#include <queue>
void __KernelEventFlagTimeout(u64 userdata, int cycleslate);
struct NativeEventFlag
{
@ -79,37 +79,162 @@ enum PspEventFlagAttributes
enum PspEventFlagWaitTypes
{
/** Wait for all bits in the pattern to be set */
PSP_EVENT_WAITAND = 0,
PSP_EVENT_WAITAND = 0x00,
/** Wait for one or more bits in the pattern to be set */
PSP_EVENT_WAITOR = 1,
PSP_EVENT_WAITOR = 0x01,
/** Clear the entire pattern when it matches. */
PSP_EVENT_WAITCLEARALL = 0x10,
/** Clear the wait pattern when it matches */
PSP_EVENT_WAITCLEAR = 0x20
PSP_EVENT_WAITCLEAR = 0x20,
PSP_EVENT_WAITKNOWN = PSP_EVENT_WAITCLEAR | PSP_EVENT_WAITCLEARALL | PSP_EVENT_WAITOR,
};
bool eventFlagInitComplete = false;
int eventFlagWaitTimer = 0;
void __KernelEventFlagInit()
{
eventFlagWaitTimer = CoreTiming::RegisterEvent("EventFlagTimeout", &__KernelEventFlagTimeout);
eventFlagInitComplete = true;
}
bool __KernelEventFlagMatches(u32 *pattern, u32 bits, u8 wait, u32 outAddr)
{
if ((wait & PSP_EVENT_WAITOR)
? (bits & *pattern) /* one or more bits of the mask */
: ((bits & *pattern) == bits)) /* all the bits of the mask */
{
if (Memory::IsValidAddress(outAddr))
Memory::Write_U32(*pattern, outAddr);
if (wait & PSP_EVENT_WAITCLEAR)
*pattern &= ~bits;
if (wait & PSP_EVENT_WAITCLEARALL)
*pattern = 0;
return true;
}
return false;
}
bool __KernelUnlockEventFlagForThread(EventFlag *e, EventFlagTh &th, u32 &error, int result, bool &wokeThreads)
{
SceUID waitID = __KernelGetWaitID(th.tid, WAITTYPE_EVENTFLAG, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(th.tid, error);
// The waitID may be different after a timeout.
if (waitID != e->GetUID())
return true;
// If result is an error code, we're just letting it go.
if (result == 0)
{
if (!__KernelEventFlagMatches(&e->nef.currentPattern, th.bits, th.wait, th.outAddr))
return false;
e->nef.numWaitThreads--;
}
else
{
// Otherwise, we set the current result since we're bailing.
if (Memory::IsValidAddress(th.outAddr))
Memory::Write_U32(e->nef.currentPattern, th.outAddr);
}
if (timeoutPtr != 0 && eventFlagWaitTimer != 0)
{
// Remove any event for this thread.
u64 cyclesLeft = CoreTiming::UnscheduleEvent(eventFlagWaitTimer, th.tid);
Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
}
__KernelResumeThreadFromWait(th.tid, result);
wokeThreads = true;
return true;
}
bool __KernelClearEventFlagThreads(EventFlag *e, int reason)
{
u32 error;
bool wokeThreads = false;
std::vector<EventFlagTh>::iterator iter, end;
for (iter = e->waitingThreads.begin(), end = e->waitingThreads.end(); iter != end; ++iter)
__KernelUnlockEventFlagForThread(e, *iter, error, reason, wokeThreads);
e->waitingThreads.clear();
return wokeThreads;
}
//SceUID sceKernelCreateEventFlag(const char *name, int attr, int bits, SceKernelEventFlagOptParam *opt);
int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPattern, u32 optPtr)
{
if (!eventFlagInitComplete)
__KernelEventFlagInit();
if (!name)
{
WARN_LOG(HLE, "%08x=sceKernelCreateEventFlag(): invalid name", SCE_KERNEL_ERROR_ERROR);
return SCE_KERNEL_ERROR_ERROR;
}
// These attributes aren't valid.
if ((flag_attr & 0x100) != 0 || flag_attr >= 0x300)
{
WARN_LOG(HLE, "%08x=sceKernelCreateEventFlag(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, flag_attr);
return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
}
EventFlag *e = new EventFlag();
SceUID id = kernelObjects.Create(e);
e->nef.size = sizeof(NativeEventFlag);
strncpy(e->nef.name, name, 32);
strncpy(e->nef.name, name, 31);
e->nef.name[31] = 0;
e->nef.attr = flag_attr;
e->nef.initPattern = flag_initPattern;
e->nef.currentPattern = e->nef.initPattern;
e->nef.numWaitThreads = 0;
DEBUG_LOG(HLE,"%i=sceKernelCreateEventFlag(\"%s\", %08x, %08x, %08x)", id, e->nef.name, e->nef.attr, e->nef.currentPattern, optPtr);
DEBUG_LOG(HLE, "%i=sceKernelCreateEventFlag(\"%s\", %08x, %08x, %08x)", id, e->nef.name, e->nef.attr, e->nef.currentPattern, optPtr);
if (optPtr != 0)
WARN_LOG(HLE, "sceKernelCreateEventFlag(%s) unsupported options parameter: %08x", name, optPtr);
if ((flag_attr & ~PSP_EVENT_WAITMULTIPLE) != 0)
WARN_LOG(HLE, "sceKernelCreateEventFlag(%s) unsupported attr parameter: %08x", name, flag_attr);
return id;
}
u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr)
{
DEBUG_LOG(HLE, "sceKernelCancelEventFlag(%i, %08X, %08X)", uid, pattern, numWaitThreadsPtr);
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(uid, error);
if (e)
{
if (Memory::IsValidAddress(numWaitThreadsPtr))
Memory::Write_U32(e->nef.numWaitThreads, numWaitThreadsPtr);
e->nef.currentPattern = pattern;
e->nef.numWaitThreads = 0;
if (__KernelClearEventFlagThreads(e, SCE_KERNEL_ERROR_WAIT_CANCEL))
hleReSchedule("event flag canceled");
return 0;
}
else
return error;
}
u32 sceKernelClearEventFlag(SceUID id, u32 bits)
{
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
if (e)
{
DEBUG_LOG(HLE,"sceKernelClearEventFlag(%i, %08x)", id, bits);
DEBUG_LOG(HLE, "sceKernelClearEventFlag(%i, %08x)", id, bits);
e->nef.currentPattern &= bits;
// Note that it's not possible for threads to get woken up by this action.
return 0;
@ -123,30 +248,26 @@ u32 sceKernelClearEventFlag(SceUID id, u32 bits)
u32 sceKernelDeleteEventFlag(SceUID uid)
{
DEBUG_LOG(HLE,"sceKernelDeleteEventFlag(%i)", uid);
return kernelObjects.Destroy<EventFlag>(uid);
}
DEBUG_LOG(HLE, "sceKernelDeleteEventFlag(%i)", uid);
u8 __KernelEventFlagMatches(u32 *pattern, u32 bits, u8 wait, u32 outAddr)
{
if ((wait & PSP_EVENT_WAITOR)
? (bits & *pattern) /* one or more bits of the mask */
: ((bits & *pattern) == bits)) /* all the bits of the mask */
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(uid, error);
if (e)
{
if (Memory::IsValidAddress(outAddr))
Memory::Write_U32(*pattern, outAddr);
bool wokeThreads = __KernelClearEventFlagThreads(e, SCE_KERNEL_ERROR_WAIT_DELETE);
if (wokeThreads)
hleReSchedule("event flag deleted");
if (wait & PSP_EVENT_WAITCLEAR)
*pattern &= ~bits;
return 1;
return kernelObjects.Destroy<EventFlag>(uid);
}
return 0;
}
else
return error;
}
u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet)
{
u32 error;
DEBUG_LOG(HLE,"sceKernelSetEventFlag(%i, %08x)", id, bitsToSet);
DEBUG_LOG(HLE, "sceKernelSetEventFlag(%i, %08x)", id, bitsToSet);
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
if (e)
{
@ -154,19 +275,20 @@ u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet)
e->nef.currentPattern |= bitsToSet;
retry:
for (size_t i = 0; i < e->waitingThreads.size(); i++)
for (size_t i = 0; i < e->waitingThreads.size(); ++i)
{
EventFlagTh *t = &e->waitingThreads[i];
if (__KernelEventFlagMatches(&e->nef.currentPattern, t->bits, t->wait, t->outAddr))
if (__KernelUnlockEventFlagForThread(e, *t, error, 0, wokeThreads))
{
__KernelResumeThreadFromWait(t->tid);
wokeThreads = true;
e->nef.numWaitThreads--;
e->waitingThreads.erase(e->waitingThreads.begin() + i);
goto retry;
// Try the one that used to be in this place next.
--i;
}
}
if (wokeThreads)
hleReSchedule("event flag set");
return 0;
}
else
@ -175,43 +297,80 @@ retry:
}
}
// Actually RETURNs a u32
void sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
void __KernelEventFlagTimeout(u64 userdata, int cycleslate)
{
DEBUG_LOG(HLE,"sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
SceUID threadID = (SceUID)userdata;
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID flagID = __KernelGetWaitID(threadID, WAITTYPE_EVENTFLAG, error);
EventFlag *e = kernelObjects.Get<EventFlag>(flagID, error);
if (e)
{
EventFlagTh th;
if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr))
for (size_t i = 0; i < e->waitingThreads.size(); i++)
{
// No match - must wait.
e->nef.numWaitThreads++;
th.tid = __KernelGetCurThread();
th.bits = bits;
th.wait = wait;
th.outAddr = outBitsPtr;
e->waitingThreads.push_back(th);
u32 timeout;
if (Memory::IsValidAddress(timeoutPtr))
timeout = Memory::Read_U32(timeoutPtr);
EventFlagTh *t = &e->waitingThreads[i];
if (t->tid == threadID)
{
bool wokeThreads;
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, 0, false); // sets RETURN
// Do not set RETURN here; it's already set for us and we'd overwrite the wrong thread's RETURN
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelUnlockEventFlagForThread(e, *t, error, SCE_KERNEL_ERROR_WAIT_TIMEOUT, wokeThreads);
e->nef.numWaitThreads--;
break;
}
}
}
else
{
RETURN(error);
}
}
// Actually RETURNs a u32
void sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr)
{
DEBUG_LOG(HLE,"sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
if (timeoutPtr == 0 || eventFlagWaitTimer == 0)
return;
int micro = (int) Memory::Read_U32(timeoutPtr);
// This seems like the actual timing of timeouts on hardware.
if (micro <= 1)
micro = 5;
else if (micro <= 209)
micro = 240;
// This should call __KernelEventFlagTimeout() later, unless we cancel it.
CoreTiming::ScheduleEvent(usToCycles(micro), eventFlagWaitTimer, __KernelGetCurThread());
}
void __KernelEventFlagRemoveThread(EventFlag *e, SceUID threadID)
{
for (size_t i = 0; i < e->waitingThreads.size(); i++)
{
EventFlagTh *t = &e->waitingThreads[i];
if (t->tid == threadID)
{
e->waitingThreads.erase(e->waitingThreads.begin() + i);
break;
}
}
}
int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
{
DEBUG_LOG(HLE, "sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
{
WARN_LOG(HLE, "sceKernelWaitEventFlag(%i) invalid mode parameter: %08x", id, wait);
return SCE_KERNEL_ERROR_ILLEGAL_MODE;
}
// Can't wait on 0, that's guaranteed to wait forever.
if (bits == 0)
return SCE_KERNEL_ERROR_EVF_ILPAT;
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
@ -220,29 +379,112 @@ void sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
EventFlagTh th;
if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr))
{
// If this thread was left in waitingThreads after a timeout, remove it.
// Otherwise we might write the outBitsPtr in the wrong place.
__KernelEventFlagRemoveThread(e, __KernelGetCurThread());
u32 timeout = 0xFFFFFFFF;
if (Memory::IsValidAddress(timeoutPtr))
timeout = Memory::Read_U32(timeoutPtr);
// Do we allow more than one thread to wait?
if (e->nef.numWaitThreads > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0)
return SCE_KERNEL_ERROR_EVF_MULTI;
// No match - must wait.
e->nef.numWaitThreads++;
th.tid = __KernelGetCurThread();
th.bits = bits;
th.wait = wait;
th.outAddr = outBitsPtr;
// If < 5ms, sometimes hardware doesn't write this, but it's unpredictable.
th.outAddr = timeout == 0 ? NULL : outBitsPtr;
e->waitingThreads.push_back(th);
u32 timeout;
if (Memory::IsValidAddress(timeoutPtr))
timeout = Memory::Read_U32(timeoutPtr);
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, 0, true); // sets RETURN
__KernelSetEventFlagTimeout(e, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, false);
}
return 0;
}
else
{
RETURN(error);
return error;
}
}
int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
{
DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
{
WARN_LOG(HLE, "sceKernelWaitEventFlagCB(%i) invalid mode parameter: %08x", id, wait);
return SCE_KERNEL_ERROR_ILLEGAL_MODE;
}
// Can't wait on 0, that's guaranteed to wait forever.
if (bits == 0)
return SCE_KERNEL_ERROR_EVF_ILPAT;
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
if (e)
{
EventFlagTh th;
if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr))
{
// If this thread was left in waitingThreads after a timeout, remove it.
// Otherwise we might write the outBitsPtr in the wrong place.
__KernelEventFlagRemoveThread(e, __KernelGetCurThread());
u32 timeout = 0xFFFFFFFF;
if (Memory::IsValidAddress(timeoutPtr))
timeout = Memory::Read_U32(timeoutPtr);
// Do we allow more than one thread to wait?
if (e->nef.numWaitThreads > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0)
return SCE_KERNEL_ERROR_EVF_MULTI;
// No match - must wait.
e->nef.numWaitThreads++;
th.tid = __KernelGetCurThread();
th.bits = bits;
th.wait = wait;
// If < 5ms, sometimes hardware doesn't write this, but it's unpredictable.
th.outAddr = timeout == 0 ? NULL : outBitsPtr;
e->waitingThreads.push_back(th);
__KernelSetEventFlagTimeout(e, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, true);
}
else
hleCheckCurrentCallbacks();
return 0;
}
else
{
return error;
}
}
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
{
DEBUG_LOG(HLE,"sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
{
WARN_LOG(HLE, "sceKernelPollEventFlag(%i) invalid mode parameter: %08x", id, wait);
return SCE_KERNEL_ERROR_ILLEGAL_MODE;
}
// Poll seems to also fail when CLEAR and CLEARALL are used together, but not wait.
if ((wait & PSP_EVENT_WAITCLEAR) != 0 && (wait & PSP_EVENT_WAITCLEARALL) != 0)
{
WARN_LOG(HLE, "sceKernelPollEventFlag(%i) invalid mode parameter: %08x", id, wait);
return SCE_KERNEL_ERROR_ILLEGAL_MODE;
}
// Can't wait on 0, it never matches.
if (bits == 0)
return SCE_KERNEL_ERROR_EVF_ILPAT;
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
@ -252,6 +494,10 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
{
if (Memory::IsValidAddress(outBitsPtr))
Memory::Write_U32(e->nef.currentPattern, outBitsPtr);
if (e->nef.numWaitThreads > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0)
return SCE_KERNEL_ERROR_EVF_MULTI;
// No match - return that, this is polling, not waiting.
return SCE_KERNEL_ERROR_EVF_COND;
}
@ -269,7 +515,7 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
//int sceKernelReferEventFlagStatus(SceUID event, SceKernelEventFlagInfo *status);
u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr)
{
DEBUG_LOG(HLE,"sceKernelReferEventFlagStatus(%i, %08x)", id, statusPtr);
DEBUG_LOG(HLE, "sceKernelReferEventFlagStatus(%i, %08x)", id, statusPtr);
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
if (e)
@ -282,10 +528,3 @@ u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr)
return error;
}
}
// never seen this one
u32 sceKernelCancelEventFlag()
{
ERROR_LOG(HLE,"UNIMPL: sceKernelCancelEventFlag()");
return 0;
}

View File

@ -21,8 +21,8 @@ int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPatte
u32 sceKernelClearEventFlag(SceUID id, u32 bits);
u32 sceKernelDeleteEventFlag(SceUID uid);
u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet);
void sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
void sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr);
u32 sceKernelCancelEventFlag();
u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr);

View File

@ -27,6 +27,7 @@
#define PSP_MUTEX_ATTR_FIFO 0
#define PSP_MUTEX_ATTR_PRIORITY 0x100
#define PSP_MUTEX_ATTR_ALLOW_RECURSIVE 0x200
#define PSP_MUTEX_ATTR_KNOWN (PSP_MUTEX_ATTR_PRIORITY | PSP_MUTEX_ATTR_ALLOW_RECURSIVE)
// Not sure about the names of these
#define PSP_MUTEX_ERROR_NO_SUCH_MUTEX 0x800201C3
@ -187,14 +188,21 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio
__KernelMutexInit();
if (!name)
{
WARN_LOG(HLE, "%08x=sceKernelCreateMutex(): invalid name", SCE_KERNEL_ERROR_ERROR);
return SCE_KERNEL_ERROR_ERROR;
}
if (attr >= 0xC00)
{
WARN_LOG(HLE, "%08x=sceKernelCreateMutex(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr);
return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
}
if (initialCount < 0)
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1)
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
DEBUG_LOG(HLE, "sceKernelCreateMutex(%s, %08x, %d, %08x)", name, attr, initialCount, optionsPtr);
Mutex *mutex = new Mutex();
SceUID id = kernelObjects.Create(mutex);
@ -210,8 +218,12 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio
else
__KernelMutexAcquireLock(mutex, initialCount);
DEBUG_LOG(HLE, "%i=sceKernelCreateMutex(%s, %08x, %d, %08x)", id, name, attr, initialCount, optionsPtr);
if (optionsPtr != 0)
WARN_LOG(HLE, "sceKernelCreateMutex(%s) unsupported options parameter.", name);
WARN_LOG(HLE, "sceKernelCreateMutex(%s) unsupported options parameter: %08x", name, optionsPtr);
if ((attr & ~PSP_MUTEX_ATTR_KNOWN) != 0)
WARN_LOG(HLE, "sceKernelCreateMutex(%s) unsupported attr parameter: %08x", name, attr);
return id;
}
@ -342,6 +354,11 @@ void __KernelMutexTimeout(u64 userdata, int cyclesLate)
Memory::Write_U32(0, timeoutPtr);
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
// We intentionally don't remove from waitingThreads here yet.
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
}
void __KernelMutexThreadEnd(SceUID threadID)
@ -486,13 +503,20 @@ int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int init
if (!mutexInitComplete)
__KernelMutexInit();
DEBUG_LOG(HLE, "sceKernelCreateLwMutex(%08x, %s, %08x, %d, %08x)", workareaPtr, name, attr, initialCount, optionsPtr);
if (!name)
{
WARN_LOG(HLE, "%08x=sceKernelCreateLwMutex(): invalid name", SCE_KERNEL_ERROR_ERROR);
return SCE_KERNEL_ERROR_ERROR;
else if (initialCount < 0)
}
if (attr >= 0x400)
{
WARN_LOG(HLE, "%08x=sceKernelCreateLwMutex(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr);
return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
}
if (initialCount < 0)
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
else if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1)
if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1)
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
LwMutex *mutex = new LwMutex();
@ -515,8 +539,12 @@ int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int init
Memory::WriteStruct(workareaPtr, &workarea);
DEBUG_LOG(HLE, "sceKernelCreateLwMutex(%08x, %s, %08x, %d, %08x)", workareaPtr, name, attr, initialCount, optionsPtr);
if (optionsPtr != 0)
WARN_LOG(HLE, "sceKernelCreateLwMutex(%s) unsupported options parameter.", name);
WARN_LOG(HLE, "sceKernelCreateLwMutex(%s) unsupported options parameter: %08x", name, optionsPtr);
if ((attr & ~PSP_MUTEX_ATTR_KNOWN) != 0)
WARN_LOG(HLE, "sceKernelCreateLwMutex(%s) unsupported attr parameter: %08x", name, attr);
return 0;
}
@ -669,6 +697,11 @@ void __KernelLwMutexTimeout(u64 userdata, int cyclesLate)
Memory::Write_U32(0, timeoutPtr);
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
// We intentionally don't remove from waitingThreads here yet.
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
}
void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr)

View File

@ -149,7 +149,7 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
if (newCount > s->ns.maxCount)
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
if (numWaitThreadsPtr)
if (Memory::IsValidAddress(numWaitThreadsPtr))
Memory::Write_U32(s->ns.numWaitThreads, numWaitThreadsPtr);
if (newCount < 0)
@ -177,7 +177,15 @@ int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32
__KernelSemaInit();
if (!name)
{
WARN_LOG(HLE, "%08x=sceKernelCreateSema(): invalid name", SCE_KERNEL_ERROR_ERROR);
return SCE_KERNEL_ERROR_ERROR;
}
if (attr >= 0x200)
{
WARN_LOG(HLE, "%08x=sceKernelCreateSema(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr);
return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
}
Semaphore *s = new Semaphore;
SceUID id = kernelObjects.Create(s);
@ -194,7 +202,9 @@ int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32
DEBUG_LOG(HLE, "%i=sceKernelCreateSema(%s, %08x, %i, %i, %08x)", id, s->ns.name, s->ns.attr, s->ns.initCount, s->ns.maxCount, optionPtr);
if (optionPtr != 0)
WARN_LOG(HLE, "sceKernelCreateSema(%s) unsupported options parameter.", name);
WARN_LOG(HLE, "sceKernelCreateSema(%s) unsupported options parameter: %08x", name, optionPtr);
if ((attr & ~PSP_SEMA_ATTR_PRIORITY) != 0)
WARN_LOG(HLE, "sceKernelCreateSema(%s) unsupported attr parameter: %08x", name, attr);
return id;
}
@ -296,6 +306,9 @@ void __KernelSemaTimeout(u64 userdata, int cycleslate)
if (s)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
s->ns.numWaitThreads--;
}

View File

@ -184,7 +184,8 @@ u32 sceRtcGetTickResolution()
u32 sceRtcGetCurrentTick(u32 tickPtr)
{
DEBUG_LOG(HLE, "sceRtcGetCurrentTick(%08x)", tickPtr);
//Don't spam the log
//DEBUG_LOG(HLE, "sceRtcGetCurrentTick(%08x)", tickPtr);
u64 curTick = __RtcGetCurrentTick();
if (Memory::IsValidAddress(tickPtr))

View File

@ -27,15 +27,15 @@
#include "../Dialog/PSPSaveDialog.h"
#include "../Dialog/PSPMsgDialog.h"
#include "../Dialog/PSPPlaceholderDialog.h"
#include "../Dialog/PSPOskDialog.h"
PSPSaveDialog saveDialog;
PSPMsgDialog msgDialog;
PSPPlaceholderDialog oskDialog;
PSPOskDialog oskDialog;
PSPPlaceholderDialog netDialog;
void __UtilityInit()
{
SavedataParam::Init();
}
@ -66,7 +66,6 @@ void sceUtilitySavedataUpdate(u32 unknown)
return;
}
#define PSP_AV_MODULE_AVCODEC 0
#define PSP_AV_MODULE_SASCORE 1
#define PSP_AV_MODULE_ATRAC3PLUS 2 // Requires PSP_AV_MODULE_AVCODEC loading first
@ -118,29 +117,34 @@ u32 sceUtilityMsgDialogGetStatus()
// On screen keyboard
int sceUtilityOskInitStart(unsigned int)
int sceUtilityOskInitStart(u32 oskPtr)
{
DEBUG_LOG(HLE,"FAKE sceUtilityOskInitStart(%i)", PARAM(0));
oskDialog.Init();
return 0;
ERROR_LOG(HLE,"FAKE sceUtilityOskInitStart(%i)", PARAM(0));
return oskDialog.Init(oskPtr);
}
int sceUtilityOskShutdownStart()
{
DEBUG_LOG(HLE,"FAKE sceUtilityOskShutdownStart(%i)", PARAM(0));
ERROR_LOG(HLE,"FAKE sceUtilityOskShutdownStart(%i)", PARAM(0));
oskDialog.Shutdown();
return 0;
}
void sceUtilityOskUpdate(unsigned int unknown)
{
DEBUG_LOG(HLE,"FAKE sceUtilityOskUpdate(%i)", unknown);
ERROR_LOG(HLE,"FAKE sceUtilityOskUpdate(%i)", unknown);
oskDialog.Update();
}
int sceUtilityOskGetStatus()
{
return oskDialog.GetStatus();
int status = oskDialog.GetStatus();
// Seems that 4 is the cancelled status for OSK?
if (status == 4)
{
status = 5;
}
return status;
}

View File

@ -246,7 +246,6 @@ inline void Write_Float(float f, u32 address)
// Reads a zero-terminated string from memory at the address.
void GetString(std::string& _string, const u32 _Address);
u8* GetPointer(const u32 address);
bool IsValidAddress(const u32 address);

View File

@ -98,6 +98,7 @@ LOCAL_SRC_FILES := \
$(SRC)/Core/Debugger/SymbolMap.cpp \
$(SRC)/Core/Dialog/PSPDialog.cpp \
$(SRC)/Core/Dialog/PSPMsgDialog.cpp \
$(SRC)/Core/Dialog/PSPOskDialog.cpp \
$(SRC)/Core/Dialog/PSPPlaceholderDialog.cpp \
$(SRC)/Core/Dialog/PSPSaveDialog.cpp \
$(SRC)/Core/Dialog/SavedataParam.cpp \

@ -1 +1 @@
Subproject commit e9b4496e32bb592dfff14b93abf284ff20783d3c
Subproject commit b41feca84bd700770791b17bde2d0a7bf910538d

80
test.py
View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python
# Automated script to run the pspautotests test suite in PPSSPP.
import sys
@ -25,6 +25,7 @@ class Command(object):
def target():
self.process = subprocess.Popen(self.cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
self.output, _ = self.process.communicate()
self.output = self.output.decode("utf-8")
thread = threading.Thread(target=target)
thread.start()
@ -57,6 +58,15 @@ tests_good = [
"misc/testgp",
"string/string",
"gpu/callbacks/ge_callbacks",
"threads/events/events",
"threads/events/cancel/cancel",
"threads/events/clear/clear",
"threads/events/create/create",
"threads/events/delete/delete",
"threads/events/poll/poll",
"threads/events/refer/refer",
"threads/events/set/set",
"threads/events/wait/wait",
"threads/lwmutex/create/create",
"threads/lwmutex/delete/delete",
"threads/lwmutex/lock/lock",
@ -83,6 +93,7 @@ tests_good = [
"threads/semaphores/wait/wait",
"power/power",
"umd/callbacks/umd",
"umd/wait/wait",
"io/directory/directory",
]
@ -114,7 +125,6 @@ tests_next = [
"video/pmf_simple/pmf_simple",
# Currently hang or crash.
"threads/events/events",
"audio/atrac/atractest",
]
@ -138,12 +148,12 @@ tests_ignored = [
def init():
global PPSSPP_EXE
if not os.path.exists("pspautotests"):
print "Please run git submodule init; git submodule update;"
print("Please run git submodule init; git submodule update;")
sys.exit(1)
if not os.path.exists(TEST_ROOT + "cpu/cpu_alu/cpu_alu.prx"):
print "Please install the pspsdk and run make in common/ and in all the tests"
print "(checked for existence of cpu/cpu_alu/cpu_alu.prx)"
print("Please install the pspsdk and run make in common/ and in all the tests")
print("(checked for existence of cpu/cpu_alu/cpu_alu.prx)")
sys.exit(1)
for p in PPSSPP_EXECUTABLES:
@ -152,28 +162,28 @@ def init():
break
if not PPSSPP_EXE:
print "PPSSPP executable missing, please build one."
print("PPSSPP executable missing, please build one.")
sys.exit(1)
def tcprint(arg):
global teamcity_mode
if teamcity_mode:
print arg
print(arg)
def run_tests(test_list, args):
global PPSSPP_EXE, TIMEOUT
tests_passed = []
tests_failed = []
for test in test_list:
# Try prx first
expected_filename = TEST_ROOT + test + ".expected"
elf_filename = TEST_ROOT + test + ".prx"
print elf_filename
print(elf_filename)
if not os.path.exists(elf_filename):
print "WARNING: no prx, trying elf"
print("WARNING: no prx, trying elf")
elf_filename = TEST_ROOT + test + ".elf"
if not os.path.exists(elf_filename):
@ -189,7 +199,7 @@ def run_tests(test_list, args):
continue
expected_output = open(expected_filename).read().strip()
tcprint("##teamcity[testStarted name='%s' captureStandardOutput='true']" % test)
cmdline = [PPSSPP_EXE, elf_filename]
@ -199,16 +209,16 @@ def run_tests(test_list, args):
c.run(TIMEOUT)
output = c.output.strip()
if c.timeout:
print output
print "Test exceded limit of %d seconds." % TIMEOUT
print(output)
print("Test exceded limit of %d seconds." % TIMEOUT)
tcprint("##teamcity[testFailed name='%s' message='Test timeout']" % test)
tcprint("##teamcity[testFinished name='%s']" % test)
continue
if output.startswith("TESTERROR"):
print "Failed to run test " + elf_filename + "!"
print("Failed to run test " + elf_filename + "!")
tests_failed.append(test)
tcprint("##teamcity[testFailed name='%s' message='Failed to run test']" % test)
tcprint("##teamcity[testFinished name='%s']" % test)
@ -217,48 +227,48 @@ def run_tests(test_list, args):
different = False
expected_lines = [x.strip() for x in expected_output.splitlines()]
output_lines = [x.strip() for x in output.splitlines()]
for i in range(0, min(len(output_lines), len(expected_lines))):
if output_lines[i] != expected_lines[i]:
print "E%i < %s" % (i + 1, expected_lines[i])
print "O%i > %s" % (i + 1, output_lines[i])
print("E%i < %s" % (i + 1, expected_lines[i]))
print("O%i > %s" % (i + 1, output_lines[i]))
different = True
if len(output_lines) != len(expected_lines):
for i in range(len(output_lines), len(expected_lines)):
print "E%i < %s" % (i + 1, expected_lines[i])
print("E%i < %s" % (i + 1, expected_lines[i]))
for i in range(len(expected_lines), len(output_lines)):
print "O%i > %s" % (i + 1, output_lines[i])
print "*** Different number of lines!"
print("O%i > %s" % (i + 1, output_lines[i]))
print("*** Different number of lines!")
different = True
if not different:
if '-v' in args:
print "++++++++++++++ The Equal Output +++++++++++++"
print "\n".join(output_lines)
print "+++++++++++++++++++++++++++++++++++++++++++++"
print " " + test + " - passed!"
print("++++++++++++++ The Equal Output +++++++++++++")
print("\n".join(output_lines))
print("+++++++++++++++++++++++++++++++++++++++++++++")
print(" " + test + " - passed!")
tests_passed.append(test)
tcprint("##teamcity[testFinished name='%s']" % test)
else:
if '-v' in args:
print "============== output from failed " + test + " :"
print output
print "============== expected output:"
print expected_output
print "==============================="
print("============== output from failed " + test + " :")
print(output)
print("============== expected output:")
print(expected_output)
print("===============================")
tests_failed.append(test)
tcprint("##teamcity[testFailed name='%s' message='Output different from expected file']" % test)
tcprint("##teamcity[testFinished name='%s']" % test)
print "%i tests passed, %i tests failed." % (
len(tests_passed), len(tests_failed))
print("%i tests passed, %i tests failed." % (
len(tests_passed), len(tests_failed)))
if len(tests_failed):
print "Failed tests:"
print("Failed tests:")
for t in tests_failed:
print " " + t
print "Ran " + PPSSPP_EXE
print(" " + t)
print("Ran " + PPSSPP_EXE)
def main():