mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge branch 'master' into mediaengine
This commit is contained in:
commit
5ba5ceff19
128 changed files with 4911 additions and 995 deletions
|
@ -273,6 +273,17 @@ add_library(zlib STATIC
|
|||
)
|
||||
include_directories(ext/zlib)
|
||||
|
||||
add_library(snappy STATIC
|
||||
ext/snappy/snappy-c.cpp
|
||||
ext/snappy/snappy-internal.h
|
||||
ext/snappy/snappy-sinksource.h
|
||||
ext/snappy/snappy-stubs-internal.h
|
||||
ext/snappy/snappy-stubs-public.h
|
||||
ext/snappy/snappy.cpp
|
||||
ext/snappy/snappy.h
|
||||
)
|
||||
include_directories(ext/snappy)
|
||||
|
||||
add_library(etcpack STATIC
|
||||
native/ext/etcpack/etcdec.cpp
|
||||
native/ext/etcpack/etcdec.h
|
||||
|
@ -535,6 +546,8 @@ add_library(native STATIC
|
|||
native/util/random/perlin.cpp
|
||||
native/util/random/perlin.h
|
||||
native/util/random/rng.h
|
||||
native/util/text/utf8.h
|
||||
native/util/text/utf8.cpp
|
||||
native/ext/rapidxml/rapidxml.hpp
|
||||
native/ext/rapidxml/rapidxml_iterators.hpp
|
||||
native/ext/rapidxml/rapidxml_print.hpp
|
||||
|
@ -543,7 +556,7 @@ include_directories(native)
|
|||
# rapidxml is headers only so we can't make a lib specific for it
|
||||
include_directories(native/ext/rapidxml)
|
||||
target_link_libraries(native ${LIBZIP} etcpack sha1 stb_image stb_vorbis #vjson
|
||||
zlib ${GLEW_LIBRARIES})
|
||||
zlib snappy ${GLEW_LIBRARIES})
|
||||
if(ANDROID)
|
||||
target_link_libraries(native log)
|
||||
endif()
|
||||
|
@ -718,8 +731,6 @@ add_library(${CoreLibName} ${CoreLinkType}
|
|||
Core/HLE/sceSas.h
|
||||
Core/HLE/sceSsl.cpp
|
||||
Core/HLE/sceSsl.h
|
||||
Core/HLE/scesupPreAcc.cpp
|
||||
Core/HLE/scesupPreAcc.h
|
||||
Core/HLE/sceUmd.cpp
|
||||
Core/HLE/sceUmd.h
|
||||
Core/HLE/sceUsb.cpp
|
||||
|
@ -806,6 +817,8 @@ add_library(GPU OBJECT
|
|||
GPU/GPUInterface.h
|
||||
GPU/GeDisasm.cpp
|
||||
GPU/GeDisasm.h
|
||||
GPU/GPUCommon.cpp
|
||||
GPU/GPUCommon.h
|
||||
GPU/GPUState.cpp
|
||||
GPU/GPUState.h
|
||||
GPU/Math3D.cpp
|
||||
|
@ -884,7 +897,7 @@ if(WIN32)
|
|||
endif()
|
||||
|
||||
if(HEADLESS)
|
||||
add_executable(PPSSPPHeadless headless/Headless.cpp)
|
||||
add_executable(PPSSPPHeadless headless/Headless.cpp headless/StubHost.h)
|
||||
target_link_libraries(PPSSPPHeadless ${CoreLibName}
|
||||
${COCOA_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
|
||||
setup_target_project(PPSSPPHeadless headless)
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "Common.h"
|
||||
#include "FileUtil.h"
|
||||
#include "../ext/snappy/snappy-c.h"
|
||||
|
||||
template <class T>
|
||||
struct LinkedListItem : public T
|
||||
|
@ -419,9 +420,22 @@ public:
|
|||
}
|
||||
|
||||
u8 *ptr = buffer;
|
||||
u8 *buf = buffer;
|
||||
if (header.Compress) {
|
||||
u8 *uncomp_buffer = new u8[header.UncompressedSize];
|
||||
size_t uncomp_size = header.UncompressedSize;
|
||||
snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size);
|
||||
if (uncomp_size != header.UncompressedSize) {
|
||||
ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size);
|
||||
}
|
||||
ptr = uncomp_buffer;
|
||||
buf = uncomp_buffer;
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
PointerWrap p(&ptr, PointerWrap::MODE_READ);
|
||||
_class.DoState(p);
|
||||
delete[] buffer;
|
||||
delete[] buf;
|
||||
|
||||
INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str());
|
||||
return true;
|
||||
|
@ -439,33 +453,57 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool compress = true;
|
||||
|
||||
// Get data
|
||||
u8 *ptr = 0;
|
||||
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
|
||||
_class.DoState(p);
|
||||
size_t const sz = (size_t)ptr;
|
||||
std::vector<u8> buffer(sz);
|
||||
|
||||
u8 * buffer = new u8[sz];
|
||||
ptr = &buffer[0];
|
||||
p.SetMode(PointerWrap::MODE_WRITE);
|
||||
_class.DoState(p);
|
||||
|
||||
|
||||
// Create header
|
||||
SChunkHeader header;
|
||||
header.Compress = 0;
|
||||
header.Compress = compress ? 1 : 0;
|
||||
header.Revision = _Revision;
|
||||
header.ExpectedSize = (int)sz;
|
||||
header.UncompressedSize = (int)sz;
|
||||
|
||||
// Write to file
|
||||
if (!pFile.WriteArray(&header, 1))
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Failed writing header");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pFile.WriteBytes(&buffer[0], sz))
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Failed writing data");
|
||||
return false;
|
||||
if (compress) {
|
||||
size_t comp_len = snappy_max_compressed_length(sz);
|
||||
u8 *compressed_buffer = new u8[comp_len];
|
||||
snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len);
|
||||
delete [] buffer;
|
||||
header.ExpectedSize = comp_len;
|
||||
if (!pFile.WriteArray(&header, 1))
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Failed writing header");
|
||||
return false;
|
||||
}
|
||||
if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) {
|
||||
ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data");
|
||||
return false;
|
||||
} else {
|
||||
INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len);
|
||||
}
|
||||
delete [] compressed_buffer;
|
||||
} else {
|
||||
if (!pFile.WriteArray(&header, 1))
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Failed writing header");
|
||||
return false;
|
||||
}
|
||||
if (!pFile.WriteBytes(&buffer[0], sz))
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Failed writing data");
|
||||
return false;
|
||||
}
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
INFO_LOG(COMMON,"ChunkReader: Done writing %s",
|
||||
|
@ -503,6 +541,7 @@ private:
|
|||
int Revision;
|
||||
int Compress;
|
||||
int ExpectedSize;
|
||||
int UncompressedSize;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -115,7 +115,11 @@ void* AllocateMemoryPages(size_t size)
|
|||
#ifdef _WIN32
|
||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
#else
|
||||
void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
void* ptr = mmap(0, size, PROT_READ | PROT_WRITE,
|
||||
#ifndef __SYMBIAN32__
|
||||
MAP_ANON |
|
||||
#endif
|
||||
MAP_PRIVATE, -1, 0);
|
||||
#endif
|
||||
|
||||
// printf("Mapped memory at %p (size %ld)\n", ptr,
|
||||
|
|
|
@ -376,3 +376,11 @@ std::string UriEncode(const std::string & sSrc)
|
|||
delete [] pStart;
|
||||
return sResult;
|
||||
}
|
||||
|
||||
bool StringEndsWith(std::string const &fullString, std::string const &ending) {
|
||||
if (fullString.length() >= ending.length()) {
|
||||
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,4 +129,6 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
|
|||
std::string UriDecode(const std::string & sSrc);
|
||||
std::string UriEncode(const std::string & sSrc);
|
||||
|
||||
bool StringEndsWith(std::string const &fullString, std::string const &ending);
|
||||
|
||||
#endif // _STRINGUTIL_H_
|
||||
|
|
|
@ -61,7 +61,6 @@ set(SRCS
|
|||
HLE/sceSsl.cpp
|
||||
HLE/sceParseUri.cpp
|
||||
HLE/sceParseHttp.cpp
|
||||
HLE/scesupPreAcc.cpp
|
||||
HLE/sceVaudio.cpp
|
||||
HW/MemoryStick.cpp
|
||||
HW/MediaEngine.cpp
|
||||
|
|
|
@ -33,18 +33,21 @@ CConfig::~CConfig()
|
|||
void CConfig::Load(const char *iniFileName)
|
||||
{
|
||||
iniFilename_ = iniFileName;
|
||||
NOTICE_LOG(LOADER, "Loading config: %s", iniFileName);
|
||||
INFO_LOG(LOADER, "Loading config: %s", iniFileName);
|
||||
bSaveSettings = true;
|
||||
|
||||
IniFile iniFile;
|
||||
iniFile.Load(iniFileName);
|
||||
if (!iniFile.Load(iniFileName)) {
|
||||
ERROR_LOG(LOADER, "Failed to read %s. Setting config to default.", iniFileName);
|
||||
// Continue anyway to initialize the config.
|
||||
}
|
||||
|
||||
IniFile::Section *general = iniFile.GetOrCreateSection("General");
|
||||
|
||||
bSpeedLimit = false;
|
||||
general->Get("FirstRun", &bFirstRun, true);
|
||||
general->Get("AutoLoadLast", &bAutoLoadLast, false);
|
||||
general->Get("AutoRun", &bAutoRun, false);
|
||||
general->Get("AutoRun", &bAutoRun, true);
|
||||
general->Get("ConfirmOnQuit", &bConfirmOnQuit, false);
|
||||
general->Get("IgnoreBadMemAccess", &bIgnoreBadMemAccess, true);
|
||||
general->Get("CurrentDirectory", ¤tDirectory, "");
|
||||
|
@ -59,7 +62,7 @@ void CConfig::Load(const char *iniFileName)
|
|||
graphics->Get("DisplayFramebuffer", &bDisplayFramebuffer, false);
|
||||
graphics->Get("WindowZoom", &iWindowZoom, 1);
|
||||
graphics->Get("BufferedRendering", &bBufferedRendering, true);
|
||||
graphics->Get("HardwareTransform", &bHardwareTransform, false);
|
||||
graphics->Get("HardwareTransform", &bHardwareTransform, true);
|
||||
graphics->Get("LinearFiltering", &bLinearFiltering, false);
|
||||
|
||||
IniFile::Section *sound = iniFile.GetOrCreateSection("Sound");
|
||||
|
@ -69,17 +72,17 @@ void CConfig::Load(const char *iniFileName)
|
|||
control->Get("ShowStick", &bShowAnalogStick, false);
|
||||
control->Get("ShowTouchControls", &bShowTouchControls, true);
|
||||
|
||||
|
||||
// Ephemeral settings
|
||||
bDrawWireframe = false;
|
||||
}
|
||||
|
||||
void CConfig::Save()
|
||||
{
|
||||
if (g_Config.bSaveSettings && iniFilename_.size())
|
||||
{
|
||||
if (iniFilename_.size() && g_Config.bSaveSettings) {
|
||||
IniFile iniFile;
|
||||
iniFile.Load(iniFilename_.c_str());
|
||||
if (!iniFile.Load(iniFilename_.c_str())) {
|
||||
ERROR_LOG(LOADER, "Error saving config - can't read ini %s", iniFilename_.c_str());
|
||||
}
|
||||
|
||||
IniFile::Section *general = iniFile.GetOrCreateSection("General");
|
||||
general->Set("FirstRun", bFirstRun);
|
||||
|
@ -108,9 +111,12 @@ void CConfig::Save()
|
|||
control->Set("ShowStick", bShowAnalogStick);
|
||||
control->Set("ShowTouchControls", bShowTouchControls);
|
||||
|
||||
iniFile.Save(iniFilename_.c_str());
|
||||
NOTICE_LOG(LOADER, "Config saved: %s", iniFilename_.c_str());
|
||||
if (!iniFile.Save(iniFilename_.c_str())) {
|
||||
ERROR_LOG(LOADER, "Error saving config - can't write ini %s", iniFilename_.c_str());
|
||||
return;
|
||||
}
|
||||
INFO_LOG(LOADER, "Config saved: %s", iniFilename_.c_str());
|
||||
} else {
|
||||
NOTICE_LOG(LOADER, "Error saving config: %s", iniFilename_.c_str());
|
||||
INFO_LOG(LOADER, "Not saving config");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,9 +38,9 @@ public:
|
|||
// These are broken
|
||||
bool bAutoLoadLast;
|
||||
bool bFirstRun;
|
||||
bool bAutoRun;
|
||||
bool bSpeedLimit;
|
||||
bool bConfirmOnQuit;
|
||||
bool bAutoRun; // start immediately
|
||||
|
||||
// Core
|
||||
bool bIgnoreBadMemAccess;
|
||||
|
|
|
@ -88,7 +88,7 @@ void Core_Run()
|
|||
while (true)
|
||||
{
|
||||
reswitch:
|
||||
switch(coreState)
|
||||
switch (coreState)
|
||||
{
|
||||
case CORE_RUNNING:
|
||||
//1: enter a fast runloop
|
||||
|
@ -132,7 +132,7 @@ void Core_EnableStepping(bool step)
|
|||
#if defined(_DEBUG)
|
||||
host->SetDebugMode(true);
|
||||
#endif
|
||||
coreState=CORE_STEPPING;
|
||||
coreState = CORE_STEPPING;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -145,5 +145,4 @@ void Core_EnableStepping(bool step)
|
|||
m_hStepEvent.notify_one();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -116,6 +116,8 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\ext\snappy\snappy-c.cpp" />
|
||||
<ClCompile Include="..\ext\snappy\snappy.cpp" />
|
||||
<ClCompile Include="Config.cpp" />
|
||||
<ClCompile Include="Core.cpp" />
|
||||
<ClCompile Include="CoreTiming.cpp" />
|
||||
|
@ -171,7 +173,6 @@
|
|||
<ClCompile Include="HLE\sceRtc.cpp" />
|
||||
<ClCompile Include="HLE\sceSas.cpp" />
|
||||
<ClCompile Include="HLE\sceSsl.cpp" />
|
||||
<ClCompile Include="HLE\scesupPreAcc.cpp" />
|
||||
<ClCompile Include="HLE\sceUmd.cpp" />
|
||||
<ClCompile Include="HLE\sceUsb.cpp" />
|
||||
<ClCompile Include="HLE\sceUtility.cpp" />
|
||||
|
@ -261,6 +262,11 @@
|
|||
<ClCompile Include="Util\ppge_atlas.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\ext\snappy\snappy-internal.h" />
|
||||
<ClInclude Include="..\ext\snappy\snappy-sinksource.h" />
|
||||
<ClInclude Include="..\ext\snappy\snappy-stubs-internal.h" />
|
||||
<ClInclude Include="..\ext\snappy\snappy-stubs-public.h" />
|
||||
<ClInclude Include="..\ext\snappy\snappy.h" />
|
||||
<ClInclude Include="Config.h" />
|
||||
<ClInclude Include="Core.h" />
|
||||
<ClInclude Include="CoreParameter.h" />
|
||||
|
@ -320,7 +326,6 @@
|
|||
<ClInclude Include="HLE\sceRtc.h" />
|
||||
<ClInclude Include="HLE\sceSas.h" />
|
||||
<ClInclude Include="HLE\sceSsl.h" />
|
||||
<ClInclude Include="HLE\scesupPreAcc.h" />
|
||||
<ClInclude Include="HLE\sceUmd.h" />
|
||||
<ClInclude Include="HLE\sceUsb.h" />
|
||||
<ClInclude Include="HLE\sceUtility.h" />
|
||||
|
|
|
@ -43,6 +43,12 @@
|
|||
<Filter Include="Dialog">
|
||||
<UniqueIdentifier>{41034c99-9b76-477f-8a77-bffaaffd5e82}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Ext">
|
||||
<UniqueIdentifier>{1966d4a4-9a34-4a6c-946a-ebaf33633276}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Ext\Snappy">
|
||||
<UniqueIdentifier>{0b77054f-7fc7-4c33-ada3-762aecde69e5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ELF\ElfReader.cpp">
|
||||
|
@ -321,9 +327,6 @@
|
|||
<ClCompile Include="HLE\sceParseHttp.cpp">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HLE\scesupPreAcc.cpp">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HLE\sceVaudio.cpp">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClCompile>
|
||||
|
@ -354,6 +357,12 @@
|
|||
<ClCompile Include="SaveState.cpp">
|
||||
<Filter>Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\snappy\snappy-c.cpp">
|
||||
<Filter>Ext\Snappy</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\snappy\snappy.cpp">
|
||||
<Filter>Ext\Snappy</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ELF\ElfReader.h">
|
||||
|
@ -620,9 +629,6 @@
|
|||
<ClInclude Include="HLE\sceParseHttp.h">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\scesupPreAcc.h">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\sceVaudio.h">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
|
@ -653,6 +659,21 @@
|
|||
<ClInclude Include="SaveState.h">
|
||||
<Filter>Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\snappy\snappy.h">
|
||||
<Filter>Ext\Snappy</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\snappy\snappy-stubs-public.h">
|
||||
<Filter>Ext\Snappy</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\snappy\snappy-sinksource.h">
|
||||
<Filter>Ext\Snappy</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\snappy\snappy-stubs-internal.h">
|
||||
<Filter>Ext\Snappy</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\snappy\snappy-internal.h">
|
||||
<Filter>Ext\Snappy</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
|
|
|
@ -50,7 +50,7 @@ void PSPDialog::EndDraw()
|
|||
|
||||
void PSPDialog::DisplayMessage(std::string text)
|
||||
{
|
||||
PPGeDrawText(text.c_str(), 480/2, 100, PPGE_ALIGN_CENTER, 0.5f, 0xFFFFFFFF);
|
||||
PPGeDrawText(text.c_str(), 40, 30, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
int PSPDialog::Shutdown()
|
||||
|
|
|
@ -44,6 +44,13 @@ int PSPMsgDialog::Init(unsigned int paramAddr)
|
|||
}
|
||||
Memory::ReadStruct(messageDialogAddr, &messageDialog);
|
||||
|
||||
// debug info
|
||||
int optionsNotCoded = ((messageDialog.options | SCE_UTILITY_MSGDIALOG_DEBUG_OPTION_CODED) ^ SCE_UTILITY_MSGDIALOG_DEBUG_OPTION_CODED);
|
||||
if(optionsNotCoded)
|
||||
{
|
||||
ERROR_LOG(HLE,"PSPMsgDialog options not coded : 0x%08x",optionsNotCoded);
|
||||
}
|
||||
|
||||
yesnoChoice = 1;
|
||||
if (messageDialog.type == 0) // number
|
||||
{
|
||||
|
@ -56,6 +63,8 @@ int PSPMsgDialog::Init(unsigned int paramAddr)
|
|||
display = DS_MESSAGE;
|
||||
if(messageDialog.options & SCE_UTILITY_MSGDIALOG_OPTION_YESNO)
|
||||
display = DS_YESNO;
|
||||
if(messageDialog.options & SCE_UTILITY_MSGDIALOG_OPTION_OK)
|
||||
display = DS_OK;
|
||||
if(messageDialog.options & SCE_UTILITY_MSGDIALOG_OPTION_DEFAULT_NO)
|
||||
yesnoChoice = 0;
|
||||
}
|
||||
|
@ -189,6 +198,25 @@ int PSPMsgDialog::Update()
|
|||
}
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_OK:
|
||||
StartDraw();
|
||||
|
||||
DisplayMessage(text);
|
||||
|
||||
// TODO : Dialogs should take control over input and not send them to the game while displaying
|
||||
DisplayEnterBack();
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
messageDialog.buttonPressed = 3;
|
||||
}
|
||||
else if (IsButtonPressed(okButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
messageDialog.buttonPressed = 1;
|
||||
}
|
||||
EndDraw();
|
||||
break;
|
||||
default:
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
return 0;
|
||||
|
@ -208,6 +236,7 @@ int PSPMsgDialog::Shutdown()
|
|||
|
||||
void PSPMsgDialog::DoState(PointerWrap &p)
|
||||
{
|
||||
PSPDialog::DoState(p);
|
||||
p.Do(display);
|
||||
p.Do(messageDialog);
|
||||
p.Do(messageDialogAddr);
|
||||
|
|
|
@ -22,8 +22,11 @@
|
|||
#define SCE_UTILITY_MSGDIALOG_OPTION_ERROR 0 // Do nothing
|
||||
#define SCE_UTILITY_MSGDIALOG_OPTION_TEXT 0x00000001
|
||||
#define SCE_UTILITY_MSGDIALOG_OPTION_YESNO 0x00000010
|
||||
#define SCE_UTILITY_MSGDIALOG_OPTION_OK 0x00000020
|
||||
#define SCE_UTILITY_MSGDIALOG_OPTION_DEFAULT_NO 0x00000100
|
||||
|
||||
#define SCE_UTILITY_MSGDIALOG_DEBUG_OPTION_CODED 0x00000131 // OR of all options coded to display warning
|
||||
|
||||
struct pspMessageDialog
|
||||
{
|
||||
pspUtilityDialogCommon common;
|
||||
|
@ -32,7 +35,7 @@ struct pspMessageDialog
|
|||
unsigned int errorNum;
|
||||
char string[512];
|
||||
unsigned int options;
|
||||
unsigned int buttonPressed; // 0=?, 1=Yes, 2=No, 3=Back
|
||||
unsigned int buttonPressed; // 0=?, 1=Yes/OK, 2=No, 3=Back
|
||||
};
|
||||
|
||||
|
||||
|
@ -58,6 +61,7 @@ private :
|
|||
DS_MESSAGE,
|
||||
DS_ERROR,
|
||||
DS_YESNO,
|
||||
DS_OK
|
||||
};
|
||||
|
||||
DisplayState display;
|
||||
|
|
|
@ -236,6 +236,7 @@ int PSPOskDialog::Update()
|
|||
|
||||
void PSPOskDialog::DoState(PointerWrap &p)
|
||||
{
|
||||
PSPDialog::DoState(p);
|
||||
p.Do(oskParams);
|
||||
p.Do(oskData);
|
||||
p.Do(oskDesc);
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
PSPSaveDialog::PSPSaveDialog()
|
||||
: PSPDialog()
|
||||
, currentSelectedSave(0)
|
||||
, display(DS_NONE)
|
||||
, currentSelectedSave(0)
|
||||
{
|
||||
param.SetPspParam(0);
|
||||
}
|
||||
|
@ -81,9 +81,12 @@ int PSPSaveDialog::Init(int paramAddr)
|
|||
display = DS_DELETE_LIST_CHOICE;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_SIZES:
|
||||
display = DS_NONE;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_LIST:
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_FILES:
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_SIZES22:
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE:
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE:
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE:
|
||||
display = DS_NONE;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_DELETE: // This run on PSP display a list of all save on the PSP. Weird. (Not really, it's to let you free up space)
|
||||
|
@ -242,7 +245,7 @@ void PSPSaveDialog::DisplaySaveDataInfo1()
|
|||
char txt[2048];
|
||||
_dbg_assert_msg_(HLE, sizeof(txt) > sizeof(SaveFileInfo), "Local buffer is too small.");
|
||||
|
||||
sprintf(txt,"%s\n%02d/%02d/%d %02d:%02d %lld KB\n%s\n%s"
|
||||
snprintf(txt,2048,"%s\n%02d/%02d/%d %02d:%02d %lld KB\n%s\n%s"
|
||||
, param.GetFileInfo(currentSelectedSave).title
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_mday
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_mon + 1
|
||||
|
@ -266,7 +269,7 @@ void PSPSaveDialog::DisplaySaveDataInfo2()
|
|||
else
|
||||
{
|
||||
char txt[1024];
|
||||
sprintf(txt,"%s\n%02d/%02d/%d %02d:%02d\n%lld KB"
|
||||
snprintf(txt,1024,"%s\n%02d/%02d/%d %02d:%02d\n%lld KB"
|
||||
, param.GetFileInfo(currentSelectedSave).saveTitle
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_mday
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_mon + 1
|
||||
|
@ -671,10 +674,41 @@ int PSPSaveDialog::Update()
|
|||
param.GetPspParam()->result = 0;
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
break;
|
||||
// TODO: Don't know the name?
|
||||
case 12:
|
||||
// Pretend we have nothing, always.
|
||||
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_FILES:
|
||||
if(param.GetFilesList(param.GetPspParam()))
|
||||
{
|
||||
param.GetPspParam()->result = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA;
|
||||
}
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_SIZES22:
|
||||
if(param.GetSizes22(param.GetPspParam()))
|
||||
{
|
||||
param.GetPspParam()->result = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA;
|
||||
}
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE:
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE:
|
||||
if(param.Save(param.GetPspParam(),param.GetSelectedSave()))
|
||||
param.GetPspParam()->result = 0;
|
||||
else
|
||||
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA;
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE:
|
||||
if(param.Load(param.GetPspParam(),param.GetSelectedSave()))
|
||||
param.GetPspParam()->result = 0;
|
||||
else
|
||||
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; // not sure if correct code
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
break;
|
||||
default:
|
||||
|
@ -708,11 +742,15 @@ int PSPSaveDialog::Shutdown()
|
|||
|
||||
void PSPSaveDialog::DoState(PointerWrap &p)
|
||||
{
|
||||
PSPDialog::DoState(p);
|
||||
p.Do(display);
|
||||
param.DoState(p);
|
||||
p.Do(request);
|
||||
// Just reset it.
|
||||
param.SetPspParam(&request);
|
||||
bool hasParam = param.GetPspParam() != NULL;
|
||||
p.Do(hasParam);
|
||||
if (hasParam)
|
||||
param.SetPspParam(&request);
|
||||
p.Do(requestAddr);
|
||||
p.Do(currentSelectedSave);
|
||||
p.Do(yesnoChoice);
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace
|
|||
str[strLength - 1] = 0;
|
||||
}
|
||||
|
||||
bool ReadPSPFile(std::string filename, u8 *data, s64 dataSize)
|
||||
bool ReadPSPFile(std::string filename, u8 *data, s64 dataSize, s64 *readSize)
|
||||
{
|
||||
u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ);
|
||||
if (handle == 0)
|
||||
|
@ -53,6 +53,8 @@ namespace
|
|||
|
||||
int result = pspFileSystem.ReadFile(handle, data, dataSize);
|
||||
pspFileSystem.CloseFile(handle);
|
||||
if(readSize)
|
||||
*readSize = result;
|
||||
|
||||
return result != 0;
|
||||
}
|
||||
|
@ -75,14 +77,47 @@ namespace
|
|||
u8 key[16];
|
||||
int sdkVersion;
|
||||
};
|
||||
|
||||
bool PSPMatch(std::string text, std::string regexp)
|
||||
{
|
||||
if(text.empty() && regexp.empty())
|
||||
return true;
|
||||
else if(regexp == "*")
|
||||
return true;
|
||||
else if(text.empty())
|
||||
return false;
|
||||
else if(regexp.empty())
|
||||
return false;
|
||||
else if(regexp == "?" && text.length() == 1)
|
||||
return true;
|
||||
else if(text == regexp)
|
||||
return true;
|
||||
else if(regexp.data()[0] == '*')
|
||||
{
|
||||
bool res = PSPMatch(text.substr(1),regexp.substr(1));
|
||||
if(!res)
|
||||
res = PSPMatch(text.substr(1),regexp);
|
||||
return res;
|
||||
}
|
||||
else if(regexp.data()[0] == '?')
|
||||
{
|
||||
return PSPMatch(text.substr(1),regexp.substr(1));
|
||||
}
|
||||
else if(regexp.data()[0] == text.data()[0])
|
||||
{
|
||||
return PSPMatch(text.substr(1),regexp.substr(1));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SavedataParam::SavedataParam()
|
||||
: pspParam(0)
|
||||
, selectedSave(0)
|
||||
, saveDataList(0)
|
||||
, saveNameListDataCount(0)
|
||||
, saveDataListCount(0)
|
||||
, saveNameListDataCount(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -130,6 +165,8 @@ std::string SavedataParam::GetSaveName(SceUtilitySavedataParam* param)
|
|||
char saveName[21];
|
||||
memcpy(saveName,param->saveName,20);
|
||||
saveName[20] = 0;
|
||||
if(strcmp(saveName,"<>") == 0)
|
||||
return "";
|
||||
return saveName;
|
||||
}
|
||||
|
||||
|
@ -167,95 +204,137 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
|
|||
return false;
|
||||
}
|
||||
|
||||
u8 *data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->dataBuf));
|
||||
|
||||
std::string dirPath = GetSaveFilePath(param, saveId);
|
||||
|
||||
if (!pspFileSystem.GetFileInfo(dirPath).exists)
|
||||
pspFileSystem.MkDir(dirPath);
|
||||
|
||||
std::string filePath = dirPath+"/"+GetFileName(param);
|
||||
INFO_LOG(HLE,"Saving file with size %u in %s",param->dataBufSize,filePath.c_str());
|
||||
if (!WritePSPFile(filePath, data_, param->dataBufSize))
|
||||
if(param->dataBuf != 0) // Can launch save without save data in mode 13
|
||||
{
|
||||
ERROR_LOG(HLE,"Error writing file %s",filePath.c_str());
|
||||
return false;
|
||||
std::string filePath = dirPath+"/"+GetFileName(param);
|
||||
int saveSize = param->dataSize;
|
||||
if(saveSize == 0 || saveSize > param->dataBufSize)
|
||||
saveSize = param->dataBufSize; // fallback, should never use this
|
||||
INFO_LOG(HLE,"Saving file with size %u in %s",saveSize,filePath.c_str());
|
||||
u8 *data_ = (u8*)Memory::GetPointer(param->dataBuf);
|
||||
|
||||
if (!WritePSPFile(filePath, data_, saveSize))
|
||||
{
|
||||
ERROR_LOG(HLE,"Error writing file %s",filePath.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// SAVE PARAM.SFO
|
||||
ParamSFOData sfoFile;
|
||||
std::string sfopath = dirPath+"/"+sfoName;
|
||||
PSPFileInfo sfoInfo = pspFileSystem.GetFileInfo(sfopath);
|
||||
if(sfoInfo.exists) // Read old sfo if exist
|
||||
{
|
||||
// SAVE PARAM.SFO
|
||||
ParamSFOData sfoFile;
|
||||
sfoFile.SetValue("TITLE",param->sfoParam.title,128);
|
||||
sfoFile.SetValue("SAVEDATA_TITLE",param->sfoParam.savedataTitle,128);
|
||||
sfoFile.SetValue("SAVEDATA_DETAIL",param->sfoParam.detail,1024);
|
||||
sfoFile.SetValue("PARENTAL_LEVEL",param->sfoParam.parentalLevel,4);
|
||||
sfoFile.SetValue("CATEGORY","MS",4);
|
||||
sfoFile.SetValue("SAVEDATA_DIRECTORY",GetSaveDir(param,saveId),64);
|
||||
|
||||
// For each file, 32 bytes for filename, 32 bytes for file hash (0 in PPSSPP)
|
||||
u8* tmpData = new u8[3168];
|
||||
memset(tmpData, 0, 3168);
|
||||
sprintf((char*)tmpData,"%s",GetFileName(param).c_str());
|
||||
sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, 3168, 3168);
|
||||
delete[] tmpData;
|
||||
|
||||
// No crypted save, so fill with 0
|
||||
tmpData = new u8[128];
|
||||
memset(tmpData, 0, 128);
|
||||
sfoFile.SetValue("SAVEDATA_PARAMS", tmpData, 128, 128);
|
||||
delete[] tmpData;
|
||||
|
||||
u8 *sfoData;
|
||||
size_t sfoSize;
|
||||
sfoFile.WriteSFO(&sfoData,&sfoSize);
|
||||
std::string sfopath = dirPath+"/"+sfoName;
|
||||
WritePSPFile(sfopath, sfoData, sfoSize);
|
||||
delete[] sfoData;
|
||||
|
||||
// SAVE ICON0
|
||||
if (param->icon0FileData.buf)
|
||||
u8 *sfoData = new u8[(size_t)sfoInfo.size];
|
||||
size_t sfoSize = (size_t)sfoInfo.size;
|
||||
if(ReadPSPFile(sfopath,sfoData,sfoSize, NULL))
|
||||
{
|
||||
data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->icon0FileData.buf));
|
||||
std::string icon0path = dirPath+"/"+icon0Name;
|
||||
WritePSPFile(icon0path, data_, param->icon0FileData.bufSize);
|
||||
sfoFile.ReadSFO(sfoData,sfoSize);
|
||||
delete[] sfoData;
|
||||
}
|
||||
// SAVE ICON1
|
||||
if (param->icon1FileData.buf)
|
||||
}
|
||||
|
||||
// Update values
|
||||
sfoFile.SetValue("TITLE",param->sfoParam.title,128);
|
||||
sfoFile.SetValue("SAVEDATA_TITLE",param->sfoParam.savedataTitle,128);
|
||||
sfoFile.SetValue("SAVEDATA_DETAIL",param->sfoParam.detail,1024);
|
||||
sfoFile.SetValue("PARENTAL_LEVEL",param->sfoParam.parentalLevel,4);
|
||||
sfoFile.SetValue("CATEGORY","MS",4);
|
||||
sfoFile.SetValue("SAVEDATA_DIRECTORY",GetSaveDir(param,saveId),64);
|
||||
|
||||
// For each file, 13 bytes for filename, 16 bytes for file hash (0 in PPSSPP), 3 byte for padding
|
||||
const int FILE_LIST_ITEM_SIZE = 13 + 16 + 3;
|
||||
const int FILE_LIST_COUNT_MAX = 99;
|
||||
const int FILE_LIST_TOTAL_SIZE = FILE_LIST_ITEM_SIZE * FILE_LIST_COUNT_MAX;
|
||||
u32 tmpDataSize = 0;
|
||||
u8* tmpDataOrig = sfoFile.GetValueData("SAVEDATA_FILE_LIST", &tmpDataSize);
|
||||
u8* tmpData = new u8[FILE_LIST_TOTAL_SIZE];
|
||||
|
||||
if (tmpDataOrig != NULL)
|
||||
memcpy(tmpData, tmpDataOrig, tmpDataSize > FILE_LIST_TOTAL_SIZE ? FILE_LIST_TOTAL_SIZE : tmpDataSize);
|
||||
else
|
||||
memset(tmpData, 0, FILE_LIST_TOTAL_SIZE);
|
||||
|
||||
if (param->dataBuf != 0)
|
||||
{
|
||||
char *fName = (char*)tmpData;
|
||||
for(int i = 0; i < FILE_LIST_COUNT_MAX; i++)
|
||||
{
|
||||
data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->icon1FileData.buf));
|
||||
std::string icon1path = dirPath+"/"+icon1Name;
|
||||
WritePSPFile(icon1path, data_, param->icon1FileData.bufSize);
|
||||
}
|
||||
// SAVE PIC1
|
||||
if (param->pic1FileData.buf)
|
||||
{
|
||||
data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->pic1FileData.buf));
|
||||
std::string pic1path = dirPath+"/"+pic1Name;
|
||||
WritePSPFile(pic1path, data_, param->pic1FileData.bufSize);
|
||||
if(fName[0] == 0)
|
||||
break; // End of list
|
||||
if(strncmp(fName,GetFileName(param).c_str(),20) == 0)
|
||||
break; // File already in SFO
|
||||
|
||||
fName += FILE_LIST_ITEM_SIZE;
|
||||
}
|
||||
|
||||
// Save SND
|
||||
if (param->snd0FileData.buf)
|
||||
{
|
||||
data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->snd0FileData.buf));
|
||||
std::string snd0path = dirPath+"/"+snd0Name;
|
||||
WritePSPFile(snd0path, data_, param->snd0FileData.bufSize);
|
||||
}
|
||||
if (fName + 20 <= (char*)tmpData + FILE_LIST_TOTAL_SIZE)
|
||||
snprintf(fName, 20, "%s",GetFileName(param).c_str());
|
||||
}
|
||||
sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, FILE_LIST_TOTAL_SIZE, FILE_LIST_TOTAL_SIZE);
|
||||
delete[] tmpData;
|
||||
|
||||
// Save Encryption Data
|
||||
{
|
||||
EncryptFileInfo encryptInfo;
|
||||
int dataSize = sizeof(encryptInfo); // version + key + sdkVersion
|
||||
memset(&encryptInfo,0,dataSize);
|
||||
// No crypted save, so fill with 0
|
||||
tmpData = new u8[128];
|
||||
memset(tmpData, 0, 128);
|
||||
sfoFile.SetValue("SAVEDATA_PARAMS", tmpData, 128, 128);
|
||||
delete[] tmpData;
|
||||
|
||||
encryptInfo.fileVersion = 1;
|
||||
encryptInfo.sdkVersion = sceKernelGetCompiledSdkVersion();
|
||||
if(param->size > 1500)
|
||||
memcpy(encryptInfo.key,param->key,16);
|
||||
u8 *sfoData;
|
||||
size_t sfoSize;
|
||||
sfoFile.WriteSFO(&sfoData,&sfoSize);
|
||||
WritePSPFile(sfopath, sfoData, sfoSize);
|
||||
delete[] sfoData;
|
||||
|
||||
std::string encryptInfoPath = dirPath+"/"+"ENCRYPT_INFO.BIN";
|
||||
WritePSPFile(encryptInfoPath, (u8*)&encryptInfo, dataSize);
|
||||
}
|
||||
// SAVE ICON0
|
||||
if (param->icon0FileData.buf)
|
||||
{
|
||||
u8* data_ = (u8*)Memory::GetPointer(param->icon0FileData.buf);
|
||||
std::string icon0path = dirPath+"/"+icon0Name;
|
||||
WritePSPFile(icon0path, data_, param->icon0FileData.bufSize);
|
||||
}
|
||||
// SAVE ICON1
|
||||
if (param->icon1FileData.buf)
|
||||
{
|
||||
u8* data_ = (u8*)Memory::GetPointer(param->icon1FileData.buf);
|
||||
std::string icon1path = dirPath+"/"+icon1Name;
|
||||
WritePSPFile(icon1path, data_, param->icon1FileData.bufSize);
|
||||
}
|
||||
// SAVE PIC1
|
||||
if (param->pic1FileData.buf)
|
||||
{
|
||||
u8* data_ = (u8*)Memory::GetPointer(param->pic1FileData.buf);
|
||||
std::string pic1path = dirPath+"/"+pic1Name;
|
||||
WritePSPFile(pic1path, data_, param->pic1FileData.bufSize);
|
||||
}
|
||||
|
||||
// Save SND
|
||||
if (param->snd0FileData.buf)
|
||||
{
|
||||
u8* data_ = (u8*)Memory::GetPointer(param->snd0FileData.buf);
|
||||
std::string snd0path = dirPath+"/"+snd0Name;
|
||||
WritePSPFile(snd0path, data_, param->snd0FileData.bufSize);
|
||||
}
|
||||
|
||||
// Save Encryption Data
|
||||
{
|
||||
EncryptFileInfo encryptInfo;
|
||||
int dataSize = sizeof(encryptInfo); // version + key + sdkVersion
|
||||
memset(&encryptInfo,0,dataSize);
|
||||
|
||||
encryptInfo.fileVersion = 1;
|
||||
encryptInfo.sdkVersion = sceKernelGetCompiledSdkVersion();
|
||||
if(param->size > 1500)
|
||||
memcpy(encryptInfo.key,param->key,16);
|
||||
|
||||
std::string encryptInfoPath = dirPath+"/"+"ENCRYPT_INFO.BIN";
|
||||
WritePSPFile(encryptInfoPath, (u8*)&encryptInfo, dataSize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -266,7 +345,7 @@ bool SavedataParam::Load(SceUtilitySavedataParam *param, int saveId)
|
|||
return false;
|
||||
}
|
||||
|
||||
u8 *data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->dataBuf));
|
||||
u8 *data_ = (u8*)Memory::GetPointer(param->dataBuf);
|
||||
|
||||
std::string dirPath = GetSaveFilePath(param, saveId);
|
||||
if (saveId >= 0 && saveNameListDataCount > 0) // if user selection, use it
|
||||
|
@ -278,12 +357,14 @@ bool SavedataParam::Load(SceUtilitySavedataParam *param, int saveId)
|
|||
}
|
||||
|
||||
std::string filePath = dirPath+"/"+GetFileName(param);
|
||||
s64 readSize;
|
||||
INFO_LOG(HLE,"Loading file with size %u in %s",param->dataBufSize,filePath.c_str());
|
||||
if (!ReadPSPFile(filePath, data_, param->dataBufSize))
|
||||
if (!ReadPSPFile(filePath, data_, param->dataBufSize, &readSize))
|
||||
{
|
||||
ERROR_LOG(HLE,"Error reading file %s",filePath.c_str());
|
||||
return false;
|
||||
}
|
||||
param->dataSize = readSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -318,9 +399,6 @@ std::string SavedataParam::GetSpaceText(int size)
|
|||
return std::string(text);
|
||||
}
|
||||
|
||||
// From my test, PSP only answer with data for save of size 1500 (sdk < 2)
|
||||
// Perhaps changed to use mode 22 id SDK >= 2
|
||||
// For now we always return results
|
||||
bool SavedataParam::GetSizes(SceUtilitySavedataParam *param)
|
||||
{
|
||||
if (!param) {
|
||||
|
@ -394,11 +472,105 @@ bool SavedataParam::GetList(SceUtilitySavedataParam *param)
|
|||
|
||||
if (Memory::IsValidAddress(param->idListAddr))
|
||||
{
|
||||
Memory::Write_U32(0,param->idListAddr+4);
|
||||
u32 outputBuffer = Memory::Read_U32(param->idListAddr + 8);
|
||||
u32 maxFile = Memory::Read_U32(param->idListAddr + 0);
|
||||
|
||||
std::vector<PSPFileInfo> validDir;
|
||||
std::vector<PSPFileInfo> allDir = pspFileSystem.GetDirListing(savePath);
|
||||
|
||||
if (Memory::IsValidAddress(outputBuffer))
|
||||
{
|
||||
std::string searchString = GetGameName(param)+GetSaveName(param);
|
||||
for (size_t i = 0; i < allDir.size() && i < maxFile; i++)
|
||||
{
|
||||
std::string dirName = allDir[i].name;
|
||||
if(PSPMatch(dirName, searchString))
|
||||
{
|
||||
validDir.push_back(allDir[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < validDir.size(); i++)
|
||||
{
|
||||
u32 baseAddr = outputBuffer + (i*72);
|
||||
Memory::Write_U32(0x11FF,baseAddr + 0); // mode
|
||||
Memory::Write_U64(0,baseAddr + 4); // TODO ctime
|
||||
Memory::Write_U64(0,baseAddr + 12); // TODO unknow
|
||||
Memory::Write_U64(0,baseAddr + 20); // TODO atime
|
||||
Memory::Write_U64(0,baseAddr + 28); // TODO unknow
|
||||
Memory::Write_U64(0,baseAddr + 36); // TODO mtime
|
||||
Memory::Write_U64(0,baseAddr + 44); // TODO unknow
|
||||
// folder name without gamename (max 20 u8)
|
||||
std::string outName = validDir[i].name.substr(GetGameName(param).size());
|
||||
Memory::Memset(baseAddr + 52,0,20);
|
||||
Memory::Memcpy(baseAddr + 52, outName.c_str(), outName.size());
|
||||
}
|
||||
}
|
||||
// Save num of folder found
|
||||
Memory::Write_U32(validDir.size(),param->idListAddr+4);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SavedataParam::GetFilesList(SceUtilitySavedataParam *param)
|
||||
{
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 dataAddr = param->fileListAddr;
|
||||
if (!Memory::IsValidAddress(dataAddr))
|
||||
return false;
|
||||
|
||||
// TODO : Need to be checked against more game
|
||||
|
||||
u32 fileInfosAddr = Memory::Read_U32(dataAddr + 24);
|
||||
|
||||
//for Valkyria2, dataAddr+0 and dataAddr+12 has "5" for 5 files
|
||||
int numFiles = Memory::Read_U32(dataAddr+12);
|
||||
int foundFiles = 0;
|
||||
for (int i = 0; i < numFiles; i++)
|
||||
{
|
||||
// for each file (80 bytes):
|
||||
// u32 mode, u32 ??, u64 size, u64 ctime, u64 ??, u64 atime, u64 ???, u64 mtime, u64 ???
|
||||
// u8[16] filename (or 13 + padding?)
|
||||
u32 curFileInfoAddr = fileInfosAddr + i*80;
|
||||
|
||||
char fileName[16];
|
||||
strncpy(fileName, Memory::GetCharPointer(curFileInfoAddr + 64),16);
|
||||
std::string filePath = savePath + GetGameName(param) + GetSaveName(param) + "/" + fileName;
|
||||
PSPFileInfo info = pspFileSystem.GetFileInfo(filePath);
|
||||
if (info.exists)
|
||||
{
|
||||
Memory::Write_U32(0x21FF, curFileInfoAddr+0);
|
||||
Memory::Write_U64(info.size, curFileInfoAddr+8);
|
||||
Memory::Write_U64(0,curFileInfoAddr + 16); // TODO ctime
|
||||
Memory::Write_U64(0,curFileInfoAddr + 24); // TODO unknow
|
||||
Memory::Write_U64(0,curFileInfoAddr + 32); // TODO atime
|
||||
Memory::Write_U64(0,curFileInfoAddr + 40); // TODO unknow
|
||||
Memory::Write_U64(0,curFileInfoAddr + 48); // TODO mtime
|
||||
Memory::Write_U64(0,curFileInfoAddr + 56); // TODO unknow
|
||||
foundFiles++;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO : verify if return true if at least 1 file found or only if all found
|
||||
return foundFiles > 0;
|
||||
}
|
||||
|
||||
bool SavedataParam::GetSizes22(SceUtilitySavedataParam *param)
|
||||
{
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO code this
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SavedataParam::Clear()
|
||||
{
|
||||
if (saveDataList)
|
||||
|
@ -412,6 +584,7 @@ void SavedataParam::Clear()
|
|||
|
||||
delete[] saveDataList;
|
||||
saveDataList = 0;
|
||||
saveDataListCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -434,6 +607,8 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param)
|
|||
char (*saveNameListData)[20];
|
||||
if (param->saveNameList != 0)
|
||||
{
|
||||
Clear();
|
||||
|
||||
saveNameListData = (char(*)[20])Memory::GetPointer(param->saveNameList);
|
||||
|
||||
// Get number of fileName in array
|
||||
|
@ -443,7 +618,6 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param)
|
|||
saveDataListCount++;
|
||||
} while(saveNameListData[saveDataListCount][0] != 0);
|
||||
|
||||
Clear();
|
||||
saveDataList = new SaveFileInfo[saveDataListCount];
|
||||
|
||||
// get and stock file info for each file
|
||||
|
@ -482,6 +656,7 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param)
|
|||
|
||||
Clear();
|
||||
saveDataList = new SaveFileInfo[1];
|
||||
saveDataListCount = 1;
|
||||
|
||||
// get and stock file info for each file
|
||||
DEBUG_LOG(HLE,"Name : %s",GetSaveName(param).c_str());
|
||||
|
@ -532,7 +707,7 @@ void SavedataParam::SetFileInfo(int idx, PSPFileInfo &info, std::string saveName
|
|||
if (info2.exists)
|
||||
{
|
||||
u8 *textureDataPNG = new u8[(size_t)info2.size];
|
||||
ReadPSPFile(fileDataPath2, textureDataPNG, info2.size);
|
||||
ReadPSPFile(fileDataPath2, textureDataPNG, info2.size, NULL);
|
||||
unsigned char *textureData;
|
||||
int w,h;
|
||||
|
||||
|
@ -561,7 +736,7 @@ void SavedataParam::SetFileInfo(int idx, PSPFileInfo &info, std::string saveName
|
|||
if (info2.exists)
|
||||
{
|
||||
u8 *sfoParam = new u8[(size_t)info2.size];
|
||||
ReadPSPFile(fileDataPath2, sfoParam, info2.size);
|
||||
ReadPSPFile(fileDataPath2, sfoParam, info2.size, NULL);
|
||||
ParamSFOData sfoFile;
|
||||
if (sfoFile.ReadSFO(sfoParam,(size_t)info2.size))
|
||||
{
|
||||
|
@ -608,6 +783,12 @@ void SavedataParam::DoState(PointerWrap &p)
|
|||
p.Do(selectedSave);
|
||||
p.Do(saveDataListCount);
|
||||
p.Do(saveNameListDataCount);
|
||||
if (p.mode == p.MODE_READ)
|
||||
{
|
||||
if (saveDataList != NULL)
|
||||
delete [] saveDataList;
|
||||
saveDataList = new SaveFileInfo[saveDataListCount];
|
||||
}
|
||||
p.DoArray(saveDataList, saveDataListCount);
|
||||
p.DoMarker("SavedataParam");
|
||||
}
|
||||
|
|
|
@ -31,7 +31,12 @@ enum SceUtilitySavedataType
|
|||
SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE = 6,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_DELETE = 7,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_SIZES = 8,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_LIST = 11
|
||||
SCE_UTILITY_SAVEDATA_TYPE_LIST = 11,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_FILES = 12,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE = 13,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE = 15,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE = 17,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_SIZES22 = 22
|
||||
} ;
|
||||
|
||||
// title, savedataTitle, detail: parts of the unencrypted SFO
|
||||
|
@ -81,7 +86,7 @@ struct SceUtilitySavedataParam
|
|||
char unused2[3];
|
||||
|
||||
/** pointer to a buffer that will contain data file unencrypted data */
|
||||
int dataBuf; // Initially void*, but void* in 64bit system take 8 bytes.
|
||||
u32 dataBuf; // Initially void*, but void* in 64bit system take 8 bytes.
|
||||
/** size of allocated space to dataBuf */
|
||||
SceSize dataBufSize;
|
||||
SceSize dataSize; // Size of the actual save data
|
||||
|
@ -98,9 +103,9 @@ struct SceUtilitySavedataParam
|
|||
int abortStatus;
|
||||
|
||||
// Function SCE_UTILITY_SAVEDATA_TYPE_SIZES
|
||||
int msFree;
|
||||
int msData;
|
||||
int utilityData;
|
||||
u32 msFree;
|
||||
u32 msData;
|
||||
u32 utilityData;
|
||||
|
||||
char key[16];
|
||||
|
||||
|
@ -108,13 +113,13 @@ struct SceUtilitySavedataParam
|
|||
int multiStatus;
|
||||
|
||||
// Function 11 LIST
|
||||
int idListAddr;
|
||||
u32 idListAddr;
|
||||
|
||||
// Function 12 FILES
|
||||
int fileListAddr;
|
||||
u32 fileListAddr;
|
||||
|
||||
// Function 22 GETSIZES
|
||||
int sizeAddr;
|
||||
u32 sizeAddr;
|
||||
|
||||
};
|
||||
|
||||
|
@ -135,10 +140,12 @@ struct SaveFileInfo
|
|||
int textureWidth;
|
||||
int textureHeight;
|
||||
};
|
||||
|
||||
|
||||
class SavedataParam
|
||||
{
|
||||
public:
|
||||
SavedataParam();
|
||||
|
||||
static void Init();
|
||||
std::string GetSaveFilePath(SceUtilitySavedataParam* param, int saveId = -1);
|
||||
std::string GetSaveDir(SceUtilitySavedataParam* param, int saveId = -1);
|
||||
|
@ -147,6 +154,8 @@ public:
|
|||
bool Load(SceUtilitySavedataParam* param, int saveId = -1);
|
||||
bool GetSizes(SceUtilitySavedataParam* param);
|
||||
bool GetList(SceUtilitySavedataParam* param);
|
||||
bool GetFilesList(SceUtilitySavedataParam* param);
|
||||
bool GetSizes22(SceUtilitySavedataParam* param);
|
||||
|
||||
std::string GetGameName(SceUtilitySavedataParam* param);
|
||||
std::string GetSaveName(SceUtilitySavedataParam* param);
|
||||
|
@ -154,8 +163,6 @@ public:
|
|||
|
||||
static std::string GetSpaceText(int size);
|
||||
|
||||
SavedataParam();
|
||||
|
||||
int SetPspParam(SceUtilitySavedataParam* param);
|
||||
SceUtilitySavedataParam* GetPspParam();
|
||||
|
||||
|
@ -177,5 +184,4 @@ private:
|
|||
SaveFileInfo* saveDataList;
|
||||
int saveDataListCount;
|
||||
int saveNameListDataCount;
|
||||
|
||||
};
|
||||
|
|
|
@ -201,10 +201,21 @@ bool ElfReader::LoadInto(u32 loadAddress)
|
|||
}
|
||||
}
|
||||
u32 totalSize = totalEnd - totalStart;
|
||||
if (loadAddress)
|
||||
vaddr = userMemory.AllocAt(loadAddress, totalSize, "ELF");
|
||||
if (!bRelocate)
|
||||
{
|
||||
// Binary is prerelocated, load it where the first segment starts
|
||||
vaddr = userMemory.AllocAt(totalStart, totalSize, "ELF");
|
||||
}
|
||||
else if (loadAddress)
|
||||
{
|
||||
// Binary needs to be relocated: add loadAddress to the binary start address
|
||||
vaddr = userMemory.AllocAt(loadAddress + totalStart, totalSize, "ELF");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just put it where there is room
|
||||
vaddr = userMemory.Alloc(totalSize, false, "ELF");
|
||||
}
|
||||
|
||||
if (vaddr == -1) {
|
||||
ERROR_LOG(LOADER, "Failed to allocate memory for ELF!");
|
||||
|
@ -299,7 +310,7 @@ bool ElfReader::LoadInto(u32 loadAddress)
|
|||
else if (s->sh_type == SHT_REL)
|
||||
{
|
||||
DEBUG_LOG(LOADER, "Traditional relocation section found.");
|
||||
if (bRelocate)
|
||||
if (!bRelocate)
|
||||
{
|
||||
DEBUG_LOG(LOADER, "Binary is prerelocated. Skipping relocations.");
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size)
|
|||
total_size += sizeof(Header);
|
||||
|
||||
// Get size info
|
||||
for(std::map<std::string,ValueData>::iterator it = values.begin(); it != values.end(); it++)
|
||||
for (std::map<std::string,ValueData>::iterator it = values.begin(); it != values.end(); it++)
|
||||
{
|
||||
key_size += it->first.size()+1;
|
||||
data_size += it->second.max_size;
|
||||
|
@ -168,29 +168,29 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size)
|
|||
|
||||
u8* data = new u8[total_size];
|
||||
*paramsfo = data;
|
||||
memset(data,0,total_size);
|
||||
memcpy(data,&header,sizeof(Header));
|
||||
memset(data, 0, total_size);
|
||||
memcpy(data, &header, sizeof(Header));
|
||||
|
||||
// Now fill
|
||||
IndexTable *index_ptr = (IndexTable*)(data + sizeof(Header));
|
||||
u8* key_ptr = data + header.key_table_start;
|
||||
u8* data_ptr = data + header.data_table_start;
|
||||
|
||||
for(std::map<std::string,ValueData>::iterator it = values.begin(); it != values.end(); it++)
|
||||
for (std::map<std::string,ValueData>::iterator it = values.begin(); it != values.end(); it++)
|
||||
{
|
||||
u16 offset = (u16)(key_ptr - (data+header.key_table_start));
|
||||
index_ptr->key_table_offset = offset;
|
||||
offset = (u16)(data_ptr - (data+header.data_table_start));
|
||||
index_ptr->data_table_offset = offset;
|
||||
index_ptr->param_max_len = it->second.max_size;
|
||||
if(it->second.type == VT_INT)
|
||||
if (it->second.type == VT_INT)
|
||||
{
|
||||
index_ptr->param_fmt = 0x0404;
|
||||
index_ptr->param_len = 4;
|
||||
|
||||
*(int*)data_ptr = it->second.i_value;
|
||||
}
|
||||
else if(it->second.type == VT_UTF8_SPE)
|
||||
else if (it->second.type == VT_UTF8_SPE)
|
||||
{
|
||||
index_ptr->param_fmt = 0x0004;
|
||||
index_ptr->param_len = it->second.u_size;
|
||||
|
@ -198,7 +198,7 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size)
|
|||
memset(data_ptr,0,index_ptr->param_max_len);
|
||||
memcpy(data_ptr,it->second.u_value,index_ptr->param_len);
|
||||
}
|
||||
else if(it->second.type == VT_UTF8)
|
||||
else if (it->second.type == VT_UTF8)
|
||||
{
|
||||
index_ptr->param_fmt = 0x0204;
|
||||
index_ptr->param_len = it->second.s_value.size()+1;
|
||||
|
|
|
@ -33,14 +33,15 @@ public:
|
|||
|
||||
bool ReadSFO(const u8 *paramsfo, size_t size);
|
||||
bool WriteSFO(u8 **paramsfo, size_t *size);
|
||||
private:
|
||||
|
||||
private:
|
||||
enum ValueType
|
||||
{
|
||||
VT_INT,
|
||||
VT_UTF8,
|
||||
VT_UTF8_SPE // raw data in u8
|
||||
};
|
||||
|
||||
class ValueData
|
||||
{
|
||||
public:
|
||||
|
@ -62,7 +63,7 @@ private:
|
|||
if(size > 0)
|
||||
{
|
||||
u_value = new u8[size];
|
||||
memcpy(u_value,data,size);
|
||||
memcpy(u_value, data, size);
|
||||
}
|
||||
u_size = size;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@ extern "C"
|
|||
}
|
||||
|
||||
#include "../../Globals.h"
|
||||
#include "PrxDecrypter.h"
|
||||
|
||||
#define ROUNDUP16(x) (((x)+15)&~15)
|
||||
|
||||
// Thank you PSARDUMPER & JPCSP keys
|
||||
|
||||
|
@ -287,6 +290,22 @@ static const TAG_INFO g_tagInfo[] =
|
|||
{ 0xBB67C59F, g_key_GAMESHARE2xx, 0x5E, 0x5E }
|
||||
};
|
||||
|
||||
bool HasKey(int key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case 0x02: case 0x03: case 0x04: case 0x05: case 0x07: case 0x0C: case 0x0D: case 0x0E: case 0x0F:
|
||||
case 0x10: case 0x11: case 0x12:
|
||||
case 0x38: case 0x39: case 0x3A: case 0x44: case 0x4B:
|
||||
case 0x53: case 0x57: case 0x5D:
|
||||
case 0x63: case 0x64:
|
||||
return true;
|
||||
default:
|
||||
INFO_LOG(HLE, "Missing key %02X, cannot decrypt module", key);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const TAG_INFO *GetTagInfo(u32 tagFind)
|
||||
{
|
||||
for (u32 iTag = 0; iTag < sizeof(g_tagInfo)/sizeof(TAG_INFO); iTag++)
|
||||
|
@ -297,21 +316,17 @@ static const TAG_INFO *GetTagInfo(u32 tagFind)
|
|||
|
||||
static void ExtraV2Mangle(u8* buffer1, u8 codeExtra)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
static u8 __declspec(align(64)) g_dataTmp[20+0xA0];
|
||||
#else
|
||||
static u8 g_dataTmp[20+0xA0] __attribute__((aligned(0x40)));
|
||||
#endif
|
||||
u8* buffer2 = g_dataTmp; // aligned
|
||||
u8 buffer2[ROUNDUP16(0x14+0xA0)];
|
||||
|
||||
memcpy(buffer2+0x14, buffer1, 0xA0);
|
||||
|
||||
memcpy(buffer2+20, buffer1, 0xA0);
|
||||
u32* pl2 = (u32*)buffer2;
|
||||
pl2[0] = 5;
|
||||
pl2[1] = pl2[2] = 0;
|
||||
pl2[3] = codeExtra;
|
||||
pl2[4] = 0xA0;
|
||||
|
||||
sceUtilsBufferCopyWithRange(buffer2, 20+0xA0, buffer2, 20+0xA0, 7);
|
||||
sceUtilsBufferCopyWithRange(buffer2, 20+0xA0, buffer2, 20+0xA0, KIRK_CMD_DECRYPT_IV_0);
|
||||
// copy result back
|
||||
memcpy(buffer1, buffer2, 0xA0);
|
||||
}
|
||||
|
@ -323,7 +338,7 @@ static int Scramble(u32 *buf, u32 size, u32 code)
|
|||
buf[3] = code;
|
||||
buf[4] = size;
|
||||
|
||||
if (sceUtilsBufferCopyWithRange((u8*)buf, size+0x14, (u8*)buf, size+0x14, 7) < 0)
|
||||
if (sceUtilsBufferCopyWithRange((u8*)buf, size+0x14, (u8*)buf, size+0x14, KIRK_CMD_DECRYPT_IV_0) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
@ -341,6 +356,11 @@ static int DecryptPRX1(const u8* pbIn, u8* pbOut, int cbTotal, u32 tag)
|
|||
{
|
||||
return -1;
|
||||
}
|
||||
if (!HasKey(pti->code) ||
|
||||
(pti->codeExtra != 0 && !HasKey(pti->codeExtra)))
|
||||
{
|
||||
return MISSING_KEY;
|
||||
}
|
||||
|
||||
retsize = *(u32*)&pbIn[0xB0];
|
||||
|
||||
|
@ -432,7 +452,7 @@ struct TAG_INFO2
|
|||
u8 type;
|
||||
};
|
||||
|
||||
static TAG_INFO2 g_tagInfo2[] =
|
||||
static const TAG_INFO2 g_tagInfo2[] =
|
||||
{
|
||||
{ 0x4C9494F0, keys660_k1, 0x43 },
|
||||
{ 0x4C9495F0, keys660_k2, 0x43 },
|
||||
|
@ -568,7 +588,7 @@ static TAG_INFO2 g_tagInfo2[] =
|
|||
};
|
||||
|
||||
|
||||
static TAG_INFO2 *GetTagInfo2(u32 tagFind)
|
||||
static const TAG_INFO2 *GetTagInfo2(u32 tagFind)
|
||||
{
|
||||
for (u32 iTag = 0; iTag < sizeof(g_tagInfo2) / sizeof(TAG_INFO2); iTag++)
|
||||
{
|
||||
|
@ -581,22 +601,25 @@ static TAG_INFO2 *GetTagInfo2(u32 tagFind)
|
|||
return NULL; // not found
|
||||
}
|
||||
|
||||
|
||||
static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag)
|
||||
{
|
||||
TAG_INFO2 * pti = GetTagInfo2(tag);
|
||||
const TAG_INFO2 *pti = GetTagInfo2(tag);
|
||||
|
||||
if (!pti)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (!HasKey(pti->code))
|
||||
{
|
||||
return MISSING_KEY;
|
||||
}
|
||||
|
||||
int retsize = *(int *)&inbuf[0xB0];
|
||||
u8 tmp1[0x150], tmp2[0x90+0x14], tmp3[0x90+0x14], tmp4[0x20];
|
||||
|
||||
memset(tmp1, 0, 0x150);
|
||||
memset(tmp2, 0, 0x90+0x14);
|
||||
memset(tmp3, 0, 0x90+0x14);
|
||||
memset(tmp4, 0, 0x20);
|
||||
int retsize = *(const int *)&inbuf[0xB0];
|
||||
u8 tmp1[0x150] = {0};
|
||||
u8 tmp2[ROUNDUP16(0x90+0x14)] = {0};
|
||||
u8 tmp3[ROUNDUP16(0x90+0x14)] = {0};
|
||||
u8 tmp4[ROUNDUP16(0x20)] = {0};
|
||||
|
||||
if (inbuf != outbuf)
|
||||
memcpy(outbuf, inbuf, size);
|
||||
|
@ -606,7 +629,7 @@ static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag)
|
|||
return -2;
|
||||
}
|
||||
|
||||
if ((size - 0x150) < retsize)
|
||||
if (((int)size - 0x150) < retsize)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
@ -614,15 +637,16 @@ static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag)
|
|||
memcpy(tmp1, outbuf, 0x150);
|
||||
|
||||
int i, j;
|
||||
u8 *p = tmp2+0x14;
|
||||
u8 *p = tmp2 + 0x14;
|
||||
|
||||
// Writes 0x90 bytes to tmp2 + 0x14.
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
for (j = 0; j < 0x10; j++)
|
||||
{
|
||||
p[(i << 4) + j] = pti->key[j];
|
||||
}
|
||||
p[(i << 4)] = i; // really?
|
||||
p[(i << 4)] = i; // really? this is very odd
|
||||
}
|
||||
|
||||
if (Scramble((u32 *)tmp2, 0x90, pti->code) < 0)
|
||||
|
@ -724,6 +748,10 @@ int pspDecryptPRX(const u8 *inbuf, u8 *outbuf, u32 size)
|
|||
{
|
||||
kirk_init();
|
||||
int retsize = DecryptPRX1(inbuf, outbuf, size, *(u32 *)&inbuf[0xD0]);
|
||||
if (retsize == MISSING_KEY)
|
||||
{
|
||||
return MISSING_KEY;
|
||||
}
|
||||
|
||||
if (retsize <= 0)
|
||||
{
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "../../Globals.h"
|
||||
|
||||
#define MISSING_KEY -10
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
|
|
@ -38,28 +38,32 @@ public:
|
|||
|
||||
class CISOFileBlockDevice : public BlockDevice
|
||||
{
|
||||
public:
|
||||
CISOFileBlockDevice(std::string _filename);
|
||||
~CISOFileBlockDevice();
|
||||
bool ReadBlock(int blockNumber, u8 *outPtr);
|
||||
int GetNumBlocks() { return numBlocks;}
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
FILE *f;
|
||||
u32 *index;
|
||||
int indexShift;
|
||||
u32 blockSize;
|
||||
int numBlocks;
|
||||
public:
|
||||
CISOFileBlockDevice(std::string _filename);
|
||||
~CISOFileBlockDevice();
|
||||
bool ReadBlock(int blockNumber, u8 *outPtr);
|
||||
int GetNumBlocks() { return numBlocks;}
|
||||
};
|
||||
|
||||
|
||||
class FileBlockDevice : public BlockDevice
|
||||
{
|
||||
std::string filename;
|
||||
FILE *f;
|
||||
size_t filesize;
|
||||
public:
|
||||
FileBlockDevice(std::string _filename);
|
||||
~FileBlockDevice();
|
||||
bool ReadBlock(int blockNumber, u8 *outPtr);
|
||||
int GetNumBlocks() {return (int)(filesize/GetBlockSize());}
|
||||
int GetNumBlocks() {return (int)(filesize / GetBlockSize());}
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
FILE *f;
|
||||
size_t filesize;
|
||||
};
|
||||
|
|
|
@ -490,23 +490,31 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) {
|
|||
return x;
|
||||
#endif
|
||||
}
|
||||
x.type = File::IsDirectory(fullName) ? FILETYPE_NORMAL : FILETYPE_DIRECTORY;
|
||||
x.type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL;
|
||||
x.exists = true;
|
||||
|
||||
if (x.type != FILETYPE_DIRECTORY)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WIN32_FILE_ATTRIBUTE_DATA data;
|
||||
GetFileAttributesEx(fullName.c_str(), GetFileExInfoStandard, &data);
|
||||
WIN32_FILE_ATTRIBUTE_DATA data;
|
||||
GetFileAttributesEx(fullName.c_str(), GetFileExInfoStandard, &data);
|
||||
|
||||
x.size = data.nFileSizeLow | ((u64)data.nFileSizeHigh<<32);
|
||||
x.size = data.nFileSizeLow | ((u64)data.nFileSizeHigh<<32);
|
||||
#else
|
||||
x.size = File::GetSize(fullName);
|
||||
//TODO
|
||||
x.size = File::GetSize(fullName);
|
||||
//TODO
|
||||
#endif
|
||||
x.mtime = File::GetModifTime(fullName);
|
||||
x.mtime = File::GetModifTime(fullName);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
bool DirectoryFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) {
|
||||
outpath = GetLocalPath(inpath);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<PSPFileInfo> DirectoryFileSystem::GetDirListing(std::string path) {
|
||||
std::vector<PSPFileInfo> myVector;
|
||||
#ifdef _WIN32
|
||||
|
@ -541,7 +549,23 @@ std::vector<PSPFileInfo> DirectoryFileSystem::GetDirListing(std::string path) {
|
|||
break;
|
||||
}
|
||||
#else
|
||||
ERROR_LOG(HLE, "GetDirListing not implemented on non-Windows");
|
||||
DIR *dp;
|
||||
dirent *dirp;
|
||||
if((dp = opendir(GetLocalPath(path).c_str())) == NULL) {
|
||||
ERROR_LOG(HLE,"Error opening directory %s\n",path.c_str());
|
||||
return myVector;
|
||||
}
|
||||
|
||||
while ((dirp = readdir(dp)) != NULL) {
|
||||
PSPFileInfo entry;
|
||||
if(dirp->d_type == DT_DIR)
|
||||
entry.type = FILETYPE_DIRECTORY;
|
||||
else
|
||||
entry.type = FILETYPE_NORMAL;
|
||||
entry.name = dirp->d_name;
|
||||
myVector.push_back(entry);
|
||||
}
|
||||
closedir(dp);
|
||||
#endif
|
||||
return myVector;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ public:
|
|||
bool RmDir(const std::string &dirname);
|
||||
bool RenameFile(const std::string &from, const std::string &to);
|
||||
bool DeleteFile(const std::string &filename);
|
||||
bool GetHostPath(const std::string &inpath, std::string &outpath);
|
||||
|
||||
private:
|
||||
struct OpenFileEntry {
|
||||
|
|
|
@ -103,6 +103,7 @@ public:
|
|||
virtual bool RmDir(const std::string &dirname) = 0;
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to) = 0;
|
||||
virtual bool DeleteFile(const std::string &filename) = 0;
|
||||
virtual bool GetHostPath(const std::string &inpath, std::string &outpath) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -122,6 +123,7 @@ public:
|
|||
virtual bool RmDir(const std::string &dirname) {return false;}
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to) {return false;}
|
||||
virtual bool DeleteFile(const std::string &filename) {return false;}
|
||||
virtual bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ nextblock:
|
|||
if (strlen(name) == 1 && name[0] == '\x01') // ".." record
|
||||
{
|
||||
strcpy(name,"..");
|
||||
relative=true;
|
||||
relative = true;
|
||||
}
|
||||
|
||||
TreeEntry *e = new TreeEntry;
|
||||
|
@ -240,7 +240,7 @@ nextblock:
|
|||
|
||||
}
|
||||
|
||||
ISOFileSystem::TreeEntry *ISOFileSystem::GetFromPath(std::string path)
|
||||
ISOFileSystem::TreeEntry *ISOFileSystem::GetFromPath(std::string path, bool catchError)
|
||||
{
|
||||
if (path.length() == 0)
|
||||
{
|
||||
|
@ -297,7 +297,10 @@ ISOFileSystem::TreeEntry *ISOFileSystem::GetFromPath(std::string path)
|
|||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(FILESYS,"File %s not found", path.c_str());
|
||||
if (catchError)
|
||||
{
|
||||
ERROR_LOG(FILESYS,"File %s not found", path.c_str());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -502,7 +505,7 @@ PSPFileInfo ISOFileSystem::GetFileInfo(std::string filename)
|
|||
return fileInfo;
|
||||
}
|
||||
|
||||
TreeEntry *entry = GetFromPath(filename);
|
||||
TreeEntry *entry = GetFromPath(filename, false);
|
||||
PSPFileInfo x;
|
||||
if (!entry)
|
||||
{
|
||||
|
|
|
@ -27,6 +27,26 @@
|
|||
|
||||
class ISOFileSystem : public IFileSystem
|
||||
{
|
||||
public:
|
||||
ISOFileSystem(IHandleAllocator *_hAlloc, BlockDevice *_blockDevice);
|
||||
~ISOFileSystem();
|
||||
void DoState(PointerWrap &p);
|
||||
std::vector<PSPFileInfo> GetDirListing(std::string path);
|
||||
u32 OpenFile(std::string filename, FileAccess access);
|
||||
void CloseFile(u32 handle);
|
||||
size_t ReadFile(u32 handle, u8 *pointer, s64 size);
|
||||
size_t SeekFile(u32 handle, s32 position, FileMove type);
|
||||
PSPFileInfo GetFileInfo(std::string filename);
|
||||
bool OwnsHandle(u32 handle);
|
||||
|
||||
size_t WriteFile(u32 handle, const u8 *pointer, s64 size);
|
||||
bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;}
|
||||
virtual bool MkDir(const std::string &dirname) {return false;}
|
||||
virtual bool RmDir(const std::string &dirname) {return false;}
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to) {return false;}
|
||||
virtual bool DeleteFile(const std::string &filename) {return false;}
|
||||
|
||||
private:
|
||||
struct TreeEntry
|
||||
{
|
||||
TreeEntry(){}
|
||||
|
@ -67,24 +87,6 @@ class ISOFileSystem : public IFileSystem
|
|||
TreeEntry entireISO;
|
||||
|
||||
void ReadDirectory(u32 startsector, u32 dirsize, TreeEntry *root);
|
||||
TreeEntry *GetFromPath(std::string path);
|
||||
TreeEntry *GetFromPath(std::string path, bool catchError=true);
|
||||
std::string EntryFullPath(TreeEntry *e);
|
||||
|
||||
public:
|
||||
ISOFileSystem(IHandleAllocator *_hAlloc, BlockDevice *_blockDevice);
|
||||
~ISOFileSystem();
|
||||
void DoState(PointerWrap &p);
|
||||
std::vector<PSPFileInfo> GetDirListing(std::string path);
|
||||
u32 OpenFile(std::string filename, FileAccess access);
|
||||
void CloseFile(u32 handle);
|
||||
size_t ReadFile(u32 handle, u8 *pointer, s64 size);
|
||||
size_t WriteFile(u32 handle, const u8 *pointer, s64 size);
|
||||
size_t SeekFile(u32 handle, s32 position, FileMove type);
|
||||
PSPFileInfo GetFileInfo(std::string filename);
|
||||
bool OwnsHandle(u32 handle);
|
||||
|
||||
virtual bool MkDir(const std::string &dirname) {return false;}
|
||||
virtual bool RmDir(const std::string &dirname) {return false;}
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to) {return false;}
|
||||
virtual bool DeleteFile(const std::string &filename) {return false;}
|
||||
};
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <set>
|
||||
#include "Common/StringUtil.h"
|
||||
#include "MetaFileSystem.h"
|
||||
|
||||
static bool ApplyPathStringToComponentsVector(std::vector<std::string> &vector, const std::string &pathString)
|
||||
|
@ -251,14 +252,15 @@ PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename)
|
|||
}
|
||||
}
|
||||
|
||||
//TODO: Not sure where this should live. Seems a bit wrong putting it in common
|
||||
bool stringEndsWith (std::string const &fullString, std::string const &ending)
|
||||
bool MetaFileSystem::GetHostPath(const std::string &inpath, std::string &outpath)
|
||||
{
|
||||
if (fullString.length() >= ending.length()) {
|
||||
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
std::string of;
|
||||
IFileSystem *system;
|
||||
if (MapFilePath(inpath, of, &system)) {
|
||||
return system->GetHostPath(of, outpath);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<PSPFileInfo> MetaFileSystem::GetDirListing(std::string path)
|
||||
|
|
|
@ -41,6 +41,9 @@ public:
|
|||
IFileSystem *GetHandleOwner(u32 handle);
|
||||
bool MapFilePath(const std::string &inpath, std::string &outpath, IFileSystem **system);
|
||||
|
||||
// Only possible if a file system is a DirectoryFileSystem or similar.
|
||||
bool GetHostPath(const std::string &inpath, std::string &outpath);
|
||||
|
||||
std::vector<PSPFileInfo> GetDirListing(std::string path);
|
||||
u32 OpenFile(std::string filename, FileAccess access);
|
||||
void CloseFile(u32 handle);
|
||||
|
|
|
@ -29,6 +29,12 @@ template<u64 func()> void WrapU64_V() {
|
|||
currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
template<u64 func(u32)> void WrapU64_U() {
|
||||
u64 retval = func(PARAM(0));
|
||||
currentMIPS->r[2] = retval & 0xFFFFFFFF;
|
||||
currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
template<int func(u32, u64)> void WrapI_UU64() {
|
||||
u64 param_one = currentMIPS->r[6];
|
||||
param_one |= (u64)(currentMIPS->r[7]) << 32;
|
||||
|
@ -36,6 +42,13 @@ template<int func(u32, u64)> void WrapI_UU64() {
|
|||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u64)> void WrapU_UU64() {
|
||||
u64 param_one = currentMIPS->r[6];
|
||||
param_one |= (u64)(currentMIPS->r[7]) << 32;
|
||||
u32 retval = func(PARAM(0), param_one);
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, u32, u64)> void WrapI_UUU64() {
|
||||
u64 param_two = currentMIPS->r[6];
|
||||
param_two |= (u64)(currentMIPS->r[7]) << 32;
|
||||
|
@ -50,6 +63,13 @@ template<u32 func(int, s64, int)> void WrapU_II64I() {
|
|||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u64, u32, u32)> void WrapU_UU64UU() {
|
||||
u64 param_one = currentMIPS->r[6];
|
||||
param_one |= (u64)(currentMIPS->r[7]) << 32;
|
||||
u32 retval = func(PARAM(0), param_one, PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<s64 func(int, s64, int)> void WrapI64_II64I() {
|
||||
s64 param_one = currentMIPS->r[6];
|
||||
param_one |= (s64)(currentMIPS->r[7]) << 32;
|
||||
|
@ -414,6 +434,11 @@ template<u32 func(u32, u32, u32, int)> void WrapU_UUUI() {
|
|||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, int, u32)> void WrapU_UUIU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, int, int)> void WrapU_UIII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
#include "sceParseUri.h"
|
||||
#include "sceSsl.h"
|
||||
#include "sceParseHttp.h"
|
||||
#include "scesupPreAcc.h"
|
||||
#include "sceVaudio.h"
|
||||
#include "sceUsb.h"
|
||||
|
||||
|
@ -75,9 +74,9 @@ const HLEFunction FakeSysCalls[] =
|
|||
const HLEFunction UtilsForUser[] =
|
||||
{
|
||||
{0x91E4F6A7, WrapU_V<sceKernelLibcClock>, "sceKernelLibcClock"},
|
||||
{0x27CC57F0, sceKernelLibcTime, "sceKernelLibcTime"},
|
||||
{0x27CC57F0, WrapU_U<sceKernelLibcTime>, "sceKernelLibcTime"},
|
||||
{0x71EC4271, sceKernelLibcGettimeofday, "sceKernelLibcGettimeofday"},
|
||||
{0xBFA98062, WrapV_UI<sceKernelDcacheInvalidateRange>, "sceKernelDcacheInvalidateRange"},
|
||||
{0xBFA98062, WrapI_UI<sceKernelDcacheInvalidateRange>, "sceKernelDcacheInvalidateRange"},
|
||||
{0xC8186A58, 0, "sceKernelUtilsMd5Digest"},
|
||||
{0x9E5C5086, 0, "sceKernelUtilsMd5BlockInit"},
|
||||
{0x61E1E525, 0, "sceKernelUtilsMd5BlockUpdate"},
|
||||
|
@ -90,10 +89,10 @@ const HLEFunction UtilsForUser[] =
|
|||
{0x06FB8A63, 0, "sceKernelUtilsMt19937UInt"},
|
||||
{0x37FB5C42, sceKernelGetGPI, "sceKernelGetGPI"},
|
||||
{0x6AD345D7, sceKernelSetGPO, "sceKernelSetGPO"},
|
||||
{0x79D1C3FA, sceKernelDcacheWritebackAll, "sceKernelDcacheWritebackAll"},
|
||||
{0xB435DEC5, sceKernelDcacheWritebackInvalidateAll, "sceKernelDcacheWritebackInvalidateAll"},
|
||||
{0x3EE30821, WrapV_UI<sceKernelDcacheWritebackRange>, "sceKernelDcacheWritebackRange"},
|
||||
{0x34B9FA9E, WrapV_UI<sceKernelDcacheWritebackInvalidateRange>, "sceKernelDcacheWritebackInvalidateRange"},
|
||||
{0x79D1C3FA, WrapI_V<sceKernelDcacheWritebackAll>, "sceKernelDcacheWritebackAll"},
|
||||
{0xB435DEC5, WrapI_V<sceKernelDcacheWritebackInvalidateAll>, "sceKernelDcacheWritebackInvalidateAll"},
|
||||
{0x3EE30821, WrapI_UI<sceKernelDcacheWritebackRange>, "sceKernelDcacheWritebackRange"},
|
||||
{0x34B9FA9E, WrapI_UI<sceKernelDcacheWritebackInvalidateRange>, "sceKernelDcacheWritebackInvalidateRange"},
|
||||
{0xC2DF770E, 0, "sceKernelIcacheInvalidateRange"},
|
||||
{0x80001C4C, 0, "sceKernelDcacheProbe"},
|
||||
{0x16641D70, 0, "sceKernelDcacheReadTag"},
|
||||
|
@ -243,7 +242,6 @@ void RegisterAllModules() {
|
|||
Register_sceParseUri();
|
||||
Register_sceSsl();
|
||||
Register_sceParseHttp();
|
||||
Register_scesupPreAcc();
|
||||
Register_sceVaudio();
|
||||
Register_sceUsb();
|
||||
|
||||
|
|
|
@ -163,7 +163,7 @@ void __CtrlSetAnalog(float x, float y)
|
|||
if (x < -1.0f) x = -1.0f;
|
||||
if (y < -1.0f) y = -1.0f;
|
||||
ctrlCurrent.analog[0] = (u8)(x * 127.f + 128.f);
|
||||
ctrlCurrent.analog[1] = (u8)(y * 127.f + 128.f);
|
||||
ctrlCurrent.analog[1] = (u8)(-y * 127.f + 128.f);
|
||||
}
|
||||
|
||||
int __CtrlReadSingleBuffer(u32 ctrlDataPtr, bool negative)
|
||||
|
@ -361,7 +361,7 @@ u32 sceCtrlSetSamplingMode(u32 mode)
|
|||
int sceCtrlGetSamplingMode(u32 modePtr)
|
||||
{
|
||||
u32 retVal = analogEnabled == true ? CTRL_MODE_ANALOG : CTRL_MODE_DIGITAL;
|
||||
DEBUG_LOG(HLE, "%d=sceCtrlGetSamplingMode(%i)", retVal);
|
||||
DEBUG_LOG(HLE, "%d=sceCtrlGetSamplingMode(%08x)", retVal, modePtr);
|
||||
|
||||
if (Memory::IsValidAddress(modePtr))
|
||||
Memory::Write_U32(retVal, modePtr);
|
||||
|
|
|
@ -109,7 +109,6 @@ void __DisplayInit() {
|
|||
vCount = 0;
|
||||
hCount = 0;
|
||||
hCountTotal = 0;
|
||||
hasSetMode = false;
|
||||
lastFrameTime = 0;
|
||||
|
||||
InitGfxState();
|
||||
|
@ -133,6 +132,20 @@ void __DisplayDoState(PointerWrap &p) {
|
|||
p.Do(leaveVblankEvent);
|
||||
CoreTiming::RestoreRegisterEvent(leaveVblankEvent, "LeaveVBlank", &hleLeaveVblank);
|
||||
|
||||
p.Do(gstate);
|
||||
p.Do(gstate_c);
|
||||
p.Do(gpuStats);
|
||||
gpu->DoState(p);
|
||||
|
||||
ReapplyGfxState();
|
||||
|
||||
if (p.mode == p.MODE_READ) {
|
||||
if (hasSetMode) {
|
||||
gpu->InitClear();
|
||||
}
|
||||
gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat);
|
||||
}
|
||||
|
||||
p.DoMarker("sceDisplay");
|
||||
}
|
||||
|
||||
|
|
|
@ -271,6 +271,19 @@ int sceFontGetFontInfo(u32 fontHandle, u32 fontInfoPtr)
|
|||
fi.minGlyphCenterXF = 16;
|
||||
fi.minGlyphCenterXI = 16;
|
||||
fi.shadowMapLength = 0;
|
||||
fi.fontStyle.fontAttributes=1;
|
||||
fi.fontStyle.fontCountry= 1;
|
||||
fi.fontStyle.fontExpire= 1;
|
||||
fi.fontStyle.fontFamily= 1;
|
||||
//fi.fontStyle.fontFileName="asd";
|
||||
fi.fontStyle.fontH=32;
|
||||
fi.fontStyle.fontHRes=32;
|
||||
fi.fontStyle.fontLanguage=1;
|
||||
// fi.fontStyle.fontName="ppsspp";
|
||||
fi.fontStyle.fontRegion=9;
|
||||
fi.fontStyle.fontV=32;
|
||||
fi.fontStyle.fontVRes=32;
|
||||
fi.fontStyle.fontWeight= 32;
|
||||
Memory::WriteStruct(fontInfoPtr, &fi);
|
||||
}
|
||||
|
||||
|
@ -316,7 +329,13 @@ int sceFontGetCharGlyphImage(u32 libHandler, u32 charCode, u32 glyphImagePtr)
|
|||
int bytesPerLine = Memory::Read_U16(glyphImagePtr+16);
|
||||
int buffer =Memory::Read_U32(glyphImagePtr+20);
|
||||
|
||||
Memory::Memset(buffer, 0x7F, bytesPerLine*bufHeight*pixelFormat);
|
||||
for (int y= 0; y < bufHeight; y++)
|
||||
{
|
||||
for (int x=0; x<bytesPerLine; x++)
|
||||
{
|
||||
Memory::Write_U8(0xff, buffer + (x * y));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -25,22 +25,19 @@
|
|||
#include "../GPU/GPUState.h"
|
||||
#include "../GPU/GPUInterface.h"
|
||||
|
||||
// TODO: This doesn't really belong here
|
||||
static int state;
|
||||
static PspGeCallbackData ge_callback_data[16];
|
||||
static bool ge_used_callbacks[16] = {0};
|
||||
|
||||
void __GeInit()
|
||||
{
|
||||
state = 0;
|
||||
memset(&ge_used_callbacks, 0, sizeof(ge_used_callbacks));
|
||||
}
|
||||
|
||||
void __GeDoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(state);
|
||||
p.Do(gstate);
|
||||
p.Do(gstate_c);
|
||||
|
||||
ReapplyGfxState();
|
||||
gpu->InvalidateCache(0, -1);
|
||||
p.DoArray(ge_callback_data, ARRAY_SIZE(ge_callback_data));
|
||||
p.DoArray(ge_used_callbacks, ARRAY_SIZE(ge_used_callbacks));
|
||||
// Everything else is done in sceDisplay.
|
||||
p.DoMarker("sceGe");
|
||||
}
|
||||
|
||||
|
@ -66,7 +63,29 @@ u32 sceGeEdramGetSize()
|
|||
return retVal;
|
||||
}
|
||||
|
||||
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId,
|
||||
// TODO: Probably shouldn't use an interrupt?
|
||||
int __GeSubIntrBase(int callbackId)
|
||||
{
|
||||
// Negative means don't use.
|
||||
if (callbackId < 0)
|
||||
return 0;
|
||||
|
||||
if (callbackId >= (int)(ARRAY_SIZE(ge_used_callbacks)))
|
||||
{
|
||||
WARN_LOG(HLE, "Unexpected (too high) GE callback id %d, ignoring", callbackId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ge_used_callbacks[callbackId])
|
||||
{
|
||||
WARN_LOG(HLE, "Unregistered GE callback id %d, ignoring", callbackId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (callbackId + 1) << 16;
|
||||
}
|
||||
|
||||
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, int callbackId,
|
||||
u32 optParamAddr)
|
||||
{
|
||||
DEBUG_LOG(HLE,
|
||||
|
@ -74,19 +93,14 @@ u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId,
|
|||
listAddress, stallAddress, callbackId, optParamAddr);
|
||||
//if (!stallAddress)
|
||||
// stallAddress = listAddress;
|
||||
u32 listID = gpu->EnqueueList(listAddress, stallAddress);
|
||||
// HACKY
|
||||
if (listID)
|
||||
state = SCE_GE_LIST_STALLING;
|
||||
else
|
||||
state = SCE_GE_LIST_COMPLETED;
|
||||
u32 listID = gpu->EnqueueList(listAddress, stallAddress, __GeSubIntrBase(callbackId), false);
|
||||
|
||||
DEBUG_LOG(HLE, "List %i enqueued.", listID);
|
||||
//return display list ID
|
||||
return listID;
|
||||
}
|
||||
|
||||
u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId,
|
||||
u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, int callbackId,
|
||||
u32 optParamAddr)
|
||||
{
|
||||
DEBUG_LOG(HLE,
|
||||
|
@ -94,29 +108,34 @@ u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId,
|
|||
listAddress, stallAddress, callbackId, optParamAddr);
|
||||
//if (!stallAddress)
|
||||
// stallAddress = listAddress;
|
||||
u32 listID = gpu->EnqueueList(listAddress, stallAddress);
|
||||
// HACKY
|
||||
if (listID)
|
||||
state = SCE_GE_LIST_STALLING;
|
||||
else
|
||||
state = SCE_GE_LIST_COMPLETED;
|
||||
u32 listID = gpu->EnqueueList(listAddress, stallAddress, __GeSubIntrBase(callbackId), true);
|
||||
|
||||
DEBUG_LOG(HLE, "List %i enqueued.", listID);
|
||||
//return display list ID
|
||||
return listID;
|
||||
}
|
||||
|
||||
void sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress)
|
||||
int sceGeListDeQueue(u32 listID)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceGeListDeQueue(%08x)", listID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceGeListUpdateStallAddr(dlid=%i,stalladdr=%08x)",
|
||||
displayListID, stallAddress);
|
||||
|
||||
gpu->UpdateStall(displayListID, stallAddress);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceGeListSync(u32 displayListID, u32 mode) //0 : wait for completion 1:check and return
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceGeListSync(dlid=%08x, mode=%08x)", displayListID, mode);
|
||||
if(mode == 1) {
|
||||
return gpu->listStatus(displayListID);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -129,47 +148,82 @@ u32 sceGeDrawSync(u32 mode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void sceGeContinue()
|
||||
int sceGeContinue()
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceGeContinue");
|
||||
// no arguments
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceGeBreak(u32 mode)
|
||||
int sceGeBreak(u32 mode)
|
||||
{
|
||||
//mode => 0 : current dlist 1: all drawing
|
||||
ERROR_LOG(HLE, "UNIMPL sceGeBreak(mode=%d)", mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u32 sceGeSetCallback(u32 structAddr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceGeSetCallback(struct=%08x)", structAddr);
|
||||
|
||||
PspGeCallbackData ge_callback_data;
|
||||
Memory::ReadStruct(structAddr, &ge_callback_data);
|
||||
int cbID = -1;
|
||||
for (int i = 0; i < ARRAY_SIZE(ge_used_callbacks); ++i)
|
||||
if (!ge_used_callbacks[i])
|
||||
{
|
||||
cbID = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ge_callback_data.finish_func)
|
||||
if (cbID == -1)
|
||||
{
|
||||
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH,
|
||||
ge_callback_data.finish_func, ge_callback_data.finish_arg);
|
||||
sceKernelEnableSubIntr(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH);
|
||||
}
|
||||
if (ge_callback_data.signal_func)
|
||||
{
|
||||
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL,
|
||||
ge_callback_data.signal_func, ge_callback_data.signal_arg);
|
||||
sceKernelEnableSubIntr(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL);
|
||||
WARN_LOG(HLE, "sceGeSetCallback(): out of callback ids");
|
||||
return SCE_KERNEL_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// TODO: This should return a callback ID
|
||||
return 0;
|
||||
ge_used_callbacks[cbID] = true;
|
||||
Memory::ReadStruct(structAddr, &ge_callback_data[cbID]);
|
||||
|
||||
int subIntrBase = __GeSubIntrBase(cbID);
|
||||
|
||||
if (ge_callback_data[cbID].finish_func)
|
||||
{
|
||||
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_FINISH,
|
||||
ge_callback_data[cbID].finish_func, ge_callback_data[cbID].finish_arg);
|
||||
sceKernelEnableSubIntr(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_FINISH);
|
||||
}
|
||||
if (ge_callback_data[cbID].signal_func)
|
||||
{
|
||||
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL,
|
||||
ge_callback_data[cbID].signal_func, ge_callback_data[cbID].signal_arg);
|
||||
sceKernelEnableSubIntr(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL);
|
||||
}
|
||||
|
||||
return cbID;
|
||||
}
|
||||
|
||||
void sceGeUnsetCallback(u32 cbID) {
|
||||
int sceGeUnsetCallback(u32 cbID)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceGeUnsetCallback(cbid=%08x)", cbID);
|
||||
sceKernelReleaseSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH);
|
||||
sceKernelReleaseSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL);
|
||||
|
||||
if (cbID >= ARRAY_SIZE(ge_used_callbacks))
|
||||
{
|
||||
WARN_LOG(HLE, "sceGeUnsetCallback(cbid=%08x): invalid callback id", cbID);
|
||||
return SCE_KERNEL_ERROR_INVALID_ID;
|
||||
}
|
||||
|
||||
if (ge_used_callbacks[cbID])
|
||||
{
|
||||
int subIntrBase = __GeSubIntrBase(cbID);
|
||||
|
||||
sceKernelReleaseSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_FINISH);
|
||||
sceKernelReleaseSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL);
|
||||
}
|
||||
else
|
||||
WARN_LOG(HLE, "sceGeUnsetCallback(cbid=%08x): ignoring unregistered callback id", cbID);
|
||||
|
||||
ge_used_callbacks[cbID] = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Points to 512 32-bit words, where we can probably layout the context however we want
|
||||
|
@ -215,9 +269,16 @@ u32 sceGeRestoreContext(u32 ctxAddr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void sceGeGetMtx()
|
||||
int sceGeGetMtx(int type, u32 matrixPtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceGeGetMtx()");
|
||||
ERROR_LOG(HLE, "UNIMPL sceGeGetMtx(%d, %08x)", type, matrixPtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceGeGetCmd(int cmd)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceGeGetCmd()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceGeEdramSetAddrTranslation(int new_size)
|
||||
|
@ -231,23 +292,23 @@ u32 sceGeEdramSetAddrTranslation(int new_size)
|
|||
|
||||
const HLEFunction sceGe_user[] =
|
||||
{
|
||||
{0xE47E40E4,&WrapU_V<sceGeEdramGetAddr>, "sceGeEdramGetAddr"},
|
||||
{0xAB49E76A,&WrapU_UUUU<sceGeListEnQueue>, "sceGeListEnQueue"},
|
||||
{0x1C0D95A6,&WrapU_UUUU<sceGeListEnQueueHead>, "sceGeListEnQueueHead"},
|
||||
{0xE0D68148,&WrapV_UU<sceGeListUpdateStallAddr>, "sceGeListUpdateStallAddr"},
|
||||
{0x03444EB4,&WrapI_UU<sceGeListSync>, "sceGeListSync"},
|
||||
{0xB287BD61,&WrapU_U<sceGeDrawSync>, "sceGeDrawSync"},
|
||||
{0xB448EC0D,&WrapV_U<sceGeBreak>, "sceGeBreak"},
|
||||
{0x4C06E472,sceGeContinue, "sceGeContinue"},
|
||||
{0xA4FC06A4,&WrapU_U<sceGeSetCallback>, "sceGeSetCallback"},
|
||||
{0x05DB22CE,&WrapV_U<sceGeUnsetCallback>, "sceGeUnsetCallback"},
|
||||
{0x1F6752AD,&WrapU_V<sceGeEdramGetSize>, "sceGeEdramGetSize"},
|
||||
{0xB77905EA,&WrapU_I<sceGeEdramSetAddrTranslation>,"sceGeEdramSetAddrTranslation"},
|
||||
{0xDC93CFEF,0,"sceGeGetCmd"},
|
||||
{0x57C8945B,&sceGeGetMtx,"sceGeGetMtx"},
|
||||
{0x438A385A,&WrapU_U<sceGeSaveContext>,"sceGeSaveContext"},
|
||||
{0x0BF608FB,&WrapU_U<sceGeRestoreContext>,"sceGeRestoreContext"},
|
||||
{0x5FB86AB0,0,"sceGeListDeQueue"},
|
||||
{0xE47E40E4, WrapU_V<sceGeEdramGetAddr>, "sceGeEdramGetAddr"},
|
||||
{0xAB49E76A, WrapU_UUIU<sceGeListEnQueue>, "sceGeListEnQueue"},
|
||||
{0x1C0D95A6, WrapU_UUIU<sceGeListEnQueueHead>, "sceGeListEnQueueHead"},
|
||||
{0xE0D68148, WrapI_UU<sceGeListUpdateStallAddr>, "sceGeListUpdateStallAddr"},
|
||||
{0x03444EB4, WrapI_UU<sceGeListSync>, "sceGeListSync"},
|
||||
{0xB287BD61, WrapU_U<sceGeDrawSync>, "sceGeDrawSync"},
|
||||
{0xB448EC0D, WrapI_U<sceGeBreak>, "sceGeBreak"},
|
||||
{0x4C06E472, WrapI_V<sceGeContinue>, "sceGeContinue"},
|
||||
{0xA4FC06A4, WrapU_U<sceGeSetCallback>, "sceGeSetCallback"},
|
||||
{0x05DB22CE, WrapI_U<sceGeUnsetCallback>, "sceGeUnsetCallback"},
|
||||
{0x1F6752AD, WrapU_V<sceGeEdramGetSize>, "sceGeEdramGetSize"},
|
||||
{0xB77905EA, WrapU_I<sceGeEdramSetAddrTranslation>, "sceGeEdramSetAddrTranslation"},
|
||||
{0xDC93CFEF, WrapU_I<sceGeGetCmd>, "sceGeGetCmd"},
|
||||
{0x57C8945B, WrapI_IU<sceGeGetMtx>, "sceGeGetMtx"},
|
||||
{0x438A385A, WrapU_U<sceGeSaveContext>, "sceGeSaveContext"},
|
||||
{0x0BF608FB, WrapU_U<sceGeRestoreContext>, "sceGeRestoreContext"},
|
||||
{0x5FB86AB0, WrapI_U<sceGeListDeQueue>, "sceGeListDeQueue"},
|
||||
};
|
||||
|
||||
void Register_sceGe_user()
|
||||
|
|
|
@ -45,4 +45,4 @@ void __GeShutdown();
|
|||
u32 sceGeRestoreContext(u32 ctxAddr);
|
||||
u32 sceGeSaveContext(u32 ctxAddr);
|
||||
|
||||
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optParamAddr);
|
||||
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, int callbackId, u32 optParamAddr);
|
||||
|
|
|
@ -20,29 +20,44 @@
|
|||
|
||||
#include "sceCtrl.h"
|
||||
|
||||
u32 sceHprmPeekCurrentKey(u32 keyAddress)
|
||||
{
|
||||
u32 sceHprmPeekCurrentKey(u32 keyAddress) {
|
||||
INFO_LOG(HLE,"0=sceHprmPeekCurrentKey(ptr)");
|
||||
Memory::Write_U32(0, keyAddress);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: Might make sense to reflect the headphone status of the host here,
|
||||
// if the games adjust their sound.
|
||||
u32 sceHprmIsHeadphoneExist() {
|
||||
DEBUG_LOG(HLE, "sceHprmIsHeadphoneExist()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceHprmIsMicrophoneExist() {
|
||||
DEBUG_LOG(HLE, "sceHprmIsMicrophoneExist()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceHprmIsRemoteExist() {
|
||||
DEBUG_LOG(HLE, "sceHprmIsRemoteExist()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const HLEFunction sceHprm[] =
|
||||
{
|
||||
{0x089fdfa4, 0, "sceHprm_0x089fdfa4"},
|
||||
{0x1910B327, &WrapU_U<sceHprmPeekCurrentKey>, "sceHprmPeekCurrentKey"},
|
||||
{0x208DB1BD, 0, "sceHprmIsRemoteExist"},
|
||||
{0x7E69EDA4, 0, "sceHprmIsHeadphoneExist"},
|
||||
{0x219C58F1, 0, "sceHprmIsMicrophoneExist"},
|
||||
{0x208DB1BD, WrapU_V<sceHprmIsRemoteExist>, "sceHprmIsRemoteExist"},
|
||||
{0x7E69EDA4, WrapU_V<sceHprmIsHeadphoneExist>, "sceHprmIsHeadphoneExist"},
|
||||
{0x219C58F1, WrapU_V<sceHprmIsMicrophoneExist>, "sceHprmIsMicrophoneExist"},
|
||||
{0xC7154136, 0, "sceHprmRegisterCallback"},
|
||||
{0x444ED0B7, 0, "sceHprmUnregisterCallback"},
|
||||
{0x1910B327, 0, "sceHprmPeekCurrentKey"},
|
||||
{0x2BCEC83E, 0, "sceHprmPeekLatch"},
|
||||
{0x40D2F9F0, 0, "sceHprmReadLatch"},
|
||||
};
|
||||
const int sceHprmCount = ARRAY_SIZE(sceHprm);
|
||||
|
||||
void Register_sceHprm()
|
||||
{
|
||||
RegisterModule("sceHprm", sceHprmCount, sceHprm);
|
||||
RegisterModule("sceHprm", ARRAY_SIZE(sceHprm), sceHprm);
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#undef DeleteFile
|
||||
#endif
|
||||
|
||||
#include "../System.h"
|
||||
#include "../Config.h"
|
||||
#include "../Host.h"
|
||||
#include "../SaveState.h"
|
||||
#include "HLE.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
|
@ -77,12 +77,6 @@ typedef s32 SceMode;
|
|||
typedef s64 SceOff;
|
||||
typedef u64 SceIores;
|
||||
|
||||
std::string emuDebugOutput;
|
||||
|
||||
const std::string &EmuDebugOutput() {
|
||||
return emuDebugOutput;
|
||||
}
|
||||
|
||||
typedef u32 (*DeferredAction)(SceUID id, int param);
|
||||
DeferredAction defAction = 0;
|
||||
u32 defParam = 0;
|
||||
|
@ -218,6 +212,15 @@ void __IoShutdown() {
|
|||
defParam = 0;
|
||||
}
|
||||
|
||||
u32 __IoGetFileHandleFromId(u32 id, u32 &outError)
|
||||
{
|
||||
FileNode *f = kernelObjects.Get < FileNode > (id, outError);
|
||||
if (!f) {
|
||||
return -1;
|
||||
}
|
||||
return f->handle;
|
||||
}
|
||||
|
||||
u32 sceIoAssign(const char *aliasname, const char *physname, const char *devname, u32 flag) {
|
||||
ERROR_LOG(HLE, "UNIMPL sceIoAssign(%s, %s, %s, %08x, ...)", aliasname,
|
||||
physname, devname, flag);
|
||||
|
@ -644,12 +647,7 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr,
|
|||
std::string data(Memory::GetCharPointer(argAddr), argLen);
|
||||
if (PSP_CoreParameter().printfEmuLog)
|
||||
{
|
||||
printf("%s", data.c_str());
|
||||
#ifdef _WIN32
|
||||
OutputDebugString(data.c_str());
|
||||
#endif
|
||||
// Also collect the debug output
|
||||
emuDebugOutput += data;
|
||||
host->SendDebugOutput(data.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -865,6 +863,7 @@ public:
|
|||
|
||||
virtual void DoState(PointerWrap &p) {
|
||||
p.Do(name);
|
||||
p.Do(index);
|
||||
|
||||
// TODO: Is this the right way for it to wake up?
|
||||
int count = listing.size();
|
||||
|
|
|
@ -18,16 +18,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../System.h"
|
||||
#include "HLE.h"
|
||||
#include "sceKernel.h"
|
||||
|
||||
void __IoInit();
|
||||
void __IoDoState(PointerWrap &p);
|
||||
void __IoShutdown();
|
||||
u32 __IoGetFileHandleFromId(u32 id, u32 &outError);
|
||||
KernelObject *__KernelFileNodeObject();
|
||||
KernelObject *__KernelDirListingObject();
|
||||
|
||||
void Register_IoFileMgrForUser();
|
||||
void Register_StdioForUser();
|
||||
|
||||
const std::string &EmuDebugOutput();
|
||||
|
|
|
@ -80,7 +80,7 @@ void __KernelInit()
|
|||
return;
|
||||
}
|
||||
|
||||
SaveState::Init();
|
||||
__KernelTimeInit();
|
||||
__InterruptsInit();
|
||||
__KernelMemoryInit();
|
||||
__KernelThreadingInit();
|
||||
|
@ -104,6 +104,7 @@ void __KernelInit()
|
|||
__ImposeInit();
|
||||
__UsbInit();
|
||||
__FontInit();
|
||||
SaveState::Init(); // Must be after IO, as it may create a directory
|
||||
|
||||
// "Internal" PSP libraries
|
||||
__PPGeInit();
|
||||
|
@ -160,6 +161,7 @@ void __KernelDoState(PointerWrap &p)
|
|||
__KernelModuleDoState(p);
|
||||
__KernelMutexDoState(p);
|
||||
__KernelSemaDoState(p);
|
||||
__KernelTimeDoState(p);
|
||||
|
||||
__AudioDoState(p);
|
||||
__CtrlDoState(p);
|
||||
|
@ -190,20 +192,18 @@ bool __KernelIsRunning() {
|
|||
void sceKernelExitGame()
|
||||
{
|
||||
INFO_LOG(HLE,"sceKernelExitGame");
|
||||
if (PSP_CoreParameter().headLess)
|
||||
exit(0);
|
||||
else
|
||||
if (!PSP_CoreParameter().headLess)
|
||||
PanicAlert("Game exited");
|
||||
__KernelSwitchOffThread("game exited");
|
||||
Core_Stop();
|
||||
}
|
||||
|
||||
void sceKernelExitGameWithStatus()
|
||||
{
|
||||
INFO_LOG(HLE,"sceKernelExitGameWithStatus");
|
||||
if (PSP_CoreParameter().headLess)
|
||||
exit(0);
|
||||
else
|
||||
if (!PSP_CoreParameter().headLess)
|
||||
PanicAlert("Game exited (with status)");
|
||||
__KernelSwitchOffThread("game exited");
|
||||
Core_Stop();
|
||||
}
|
||||
|
||||
|
@ -247,23 +247,38 @@ void sceKernelGetGPI()
|
|||
// Don't even log these, they're spammy and we probably won't
|
||||
// need to emulate them. Might be useful for invalidating cached
|
||||
// textures, and in the future display lists, in some cases though.
|
||||
void sceKernelDcacheInvalidateRange(u32 addr, int size)
|
||||
int sceKernelDcacheInvalidateRange(u32 addr, int size)
|
||||
{
|
||||
gpu->InvalidateCache(addr, size);
|
||||
if (size > 0 && addr != 0) {
|
||||
gpu->InvalidateCache(addr, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void sceKernelDcacheWritebackAll()
|
||||
int sceKernelDcacheWritebackAll()
|
||||
{
|
||||
// Some games seem to use this a lot, it doesn't make sense
|
||||
// to zap the whole texture cache.
|
||||
// gpu->InvalidateCache(0, -1);
|
||||
return 0;
|
||||
}
|
||||
void sceKernelDcacheWritebackRange(u32 addr, int size)
|
||||
int sceKernelDcacheWritebackRange(u32 addr, int size)
|
||||
{
|
||||
if (size > 0 && addr != 0) {
|
||||
gpu->InvalidateCache(addr, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void sceKernelDcacheWritebackInvalidateRange(u32 addr, int size)
|
||||
int sceKernelDcacheWritebackInvalidateRange(u32 addr, int size)
|
||||
{
|
||||
gpu->InvalidateCache(addr, size);
|
||||
if (size > 0 && addr != 0) {
|
||||
gpu->InvalidateCache(addr, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void sceKernelDcacheWritebackInvalidateAll()
|
||||
int sceKernelDcacheWritebackInvalidateAll()
|
||||
{
|
||||
gpu->InvalidateCache(0, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
KernelObjectPool::KernelObjectPool()
|
||||
|
@ -537,21 +552,6 @@ const HLEFunction ThreadManForUser[] =
|
|||
{0x94416130,WrapU_UUUU<sceKernelGetThreadmanIdList>,"sceKernelGetThreadmanIdList"},
|
||||
{0x57CF62DD,WrapU_U<sceKernelGetThreadmanIdType>,"sceKernelGetThreadmanIdType"},
|
||||
|
||||
{0x20fff560,sceKernelCreateVTimer,"sceKernelCreateVTimer"},
|
||||
{0x328F9E52,0,"sceKernelDeleteVTimer"},
|
||||
{0xc68d9437,sceKernelStartVTimer,"sceKernelStartVTimer"},
|
||||
{0xD0AEEE87,0,"sceKernelStopVTimer"},
|
||||
{0xD2D615EF,0,"sceKernelCancelVTimerHandler"},
|
||||
{0xB3A59970,0,"sceKernelGetVTimerBase"},
|
||||
{0xB7C18B77,0,"sceKernelGetVTimerBaseWide"},
|
||||
{0x034A921F,0,"sceKernelGetVTimerTime"},
|
||||
{0xC0B3FFD2,0,"sceKernelGetVTimerTimeWide"},
|
||||
{0x5F32BEAA,0,"sceKernelReferVTimerStatus"},
|
||||
{0x542AD630,0,"sceKernelSetVTimerTime"},
|
||||
{0xFB6425C3,0,"sceKernelSetVTimerTimeWide"},
|
||||
{0xd8b299ae,sceKernelSetVTimerHandler,"sceKernelSetVTimerHandler"},
|
||||
{0x53B00E9A,0,"sceKernelSetVTimerHandlerWide"},
|
||||
|
||||
{0x82BC5777,sceKernelGetSystemTimeWide,"sceKernelGetSystemTimeWide"},
|
||||
{0xdb738f35,sceKernelGetSystemTime,"sceKernelGetSystemTime"},
|
||||
{0x369ed59d,sceKernelGetSystemTimeLow,"sceKernelGetSystemTimeLow"},
|
||||
|
@ -625,6 +625,21 @@ const HLEFunction ThreadManForUser[] =
|
|||
{0xA8AA591F,sceKernelCancelFpl,"sceKernelCancelFpl"},
|
||||
{0xD8199E4C,sceKernelReferFplStatus,"sceKernelReferFplStatus"},
|
||||
|
||||
{0x20fff560,WrapU_CU<sceKernelCreateVTimer>,"sceKernelCreateVTimer"},
|
||||
{0x328F9E52,WrapU_U<sceKernelDeleteVTimer>,"sceKernelDeleteVTimer"},
|
||||
{0xc68d9437,WrapU_U<sceKernelStartVTimer>,"sceKernelStartVTimer"},
|
||||
{0xD0AEEE87,WrapU_U<sceKernelStopVTimer>,"sceKernelStopVTimer"},
|
||||
{0xD2D615EF,WrapU_U<sceKernelCancelVTimerHandler>,"sceKernelCancelVTimerHandler"},
|
||||
{0xB3A59970,WrapU_UU<sceKernelGetVTimerBase>,"sceKernelGetVTimerBase"},
|
||||
{0xB7C18B77,WrapU64_U<sceKernelGetVTimerBaseWide>,"sceKernelGetVTimerBaseWide"},
|
||||
{0x034A921F,WrapU_UU<sceKernelGetVTimerTime>,"sceKernelGetVTimerTime"},
|
||||
{0xC0B3FFD2,WrapU64_U<sceKernelGetVTimerTimeWide>,"sceKernelGetVTimerTimeWide"},
|
||||
{0x5F32BEAA,WrapU_UU<sceKernelReferVTimerStatus>,"sceKernelReferVTimerStatus"},
|
||||
{0x542AD630,WrapU_UU<sceKernelSetVTimerTime>,"sceKernelSetVTimerTime"},
|
||||
{0xFB6425C3,WrapU_UU64<sceKernelSetVTimerTimeWide>,"sceKernelSetVTimerTimeWide"},
|
||||
{0xd8b299ae,WrapU_UUUU<sceKernelSetVTimerHandler>,"sceKernelSetVTimerHandler"},
|
||||
{0x53B00E9A,WrapU_UU64UU<sceKernelSetVTimerHandlerWide>,"sceKernelSetVTimerHandlerWide"},
|
||||
|
||||
// Not sure if these should be hooked up. See below.
|
||||
{0x0E927AED, _sceKernelReturnFromTimerHandler, "_sceKernelReturnFromTimerHandler"},
|
||||
{0x532A522E, _sceKernelExitThread,"_sceKernelExitThread"},
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
|
||||
enum
|
||||
{
|
||||
SCE_KERNEL_ERROR_OK = 0,
|
||||
SCE_KERNEL_ERROR_OK = 0,
|
||||
SCE_KERNEL_ERROR_OUT_OF_MEMORY = 0x80000022,
|
||||
SCE_KERNEL_ERROR_INVALID_ID = 0x80000100,
|
||||
SCE_KERNEL_ERROR_INVALID_VALUE = 0x800001fe,
|
||||
SCE_KERNEL_ERROR_INVALID_ARGUMENT = 0x800001ff,
|
||||
SCE_KERNEL_ERROR_ERROR = 0x80020001,
|
||||
|
@ -292,11 +294,11 @@ void sceKernelFindModuleByName();
|
|||
|
||||
void sceKernelSetGPO();
|
||||
void sceKernelGetGPI();
|
||||
void sceKernelDcacheInvalidateRange(u32 addr, int size);
|
||||
void sceKernelDcacheWritebackAll();
|
||||
void sceKernelDcacheWritebackRange(u32 addr, int size);
|
||||
void sceKernelDcacheWritebackInvalidateRange(u32 addr, int size);
|
||||
void sceKernelDcacheWritebackInvalidateAll();
|
||||
int sceKernelDcacheInvalidateRange(u32 addr, int size);
|
||||
int sceKernelDcacheWritebackAll();
|
||||
int sceKernelDcacheWritebackRange(u32 addr, int size);
|
||||
int sceKernelDcacheWritebackInvalidateRange(u32 addr, int size);
|
||||
int sceKernelDcacheWritebackInvalidateAll();
|
||||
void sceKernelGetThreadStackFreeSize();
|
||||
void sceKernelIcacheInvalidateAll();
|
||||
void sceKernelIcacheClearAll();
|
||||
|
|
|
@ -547,24 +547,37 @@ void QueryIntrHandlerInfo()
|
|||
RETURN(0);
|
||||
}
|
||||
|
||||
// TODO: speedup
|
||||
u32 sceKernelMemset(u32 addr, u32 fillc, u32 n)
|
||||
{
|
||||
u8 c = fillc & 0xff;
|
||||
DEBUG_LOG(HLE, "sceKernelMemset(ptr = %08x, c = %02x, n = %08x)", addr, c, n);
|
||||
for (size_t i = 0; i < n; i++)
|
||||
Memory::Write_U8((u8)c, addr + i);
|
||||
return 0; // TODO: verify it should return this
|
||||
Memory::Memset(addr, c, n);
|
||||
return addr;
|
||||
}
|
||||
|
||||
u32 sceKernelMemcpy(u32 dst, u32 src, u32 size)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size);
|
||||
if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(src+size)) // a bit of bound checking. Wrong??
|
||||
// Technically should crash if these are invalid and size > 0...
|
||||
if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(src + size - 1))
|
||||
{
|
||||
Memory::Memcpy(dst, Memory::GetPointer(src), size);
|
||||
u8 *dstp = Memory::GetPointer(dst);
|
||||
u8 *srcp = Memory::GetPointer(src);
|
||||
u32 size64 = size / 8;
|
||||
u32 size8 = size % 8;
|
||||
|
||||
// Try to handle overlapped copies with similar properties to hardware, just in case.
|
||||
// Not that anyone ought to rely on it.
|
||||
while (size64-- > 0)
|
||||
{
|
||||
*(u64 *) dstp = *(u64 *) srcp;
|
||||
srcp += 8;
|
||||
dstp += 8;
|
||||
}
|
||||
while (size8-- > 0)
|
||||
*dstp++ = *srcp++;
|
||||
}
|
||||
return 0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
const HLEFunction Kernel_Library[] =
|
||||
|
|
|
@ -71,10 +71,10 @@ struct PendingInterrupt {
|
|||
PendingInterrupt(int intr_, int subintr_, int arg_)
|
||||
: intr(intr_), subintr(subintr_), hasArg(true), arg(arg_) {}
|
||||
|
||||
int arg;
|
||||
u32 intr;
|
||||
u32 subintr;
|
||||
bool hasArg;
|
||||
int intr;
|
||||
int subintr;
|
||||
int arg;
|
||||
};
|
||||
|
||||
class SubIntrHandler
|
||||
|
|
|
@ -55,6 +55,12 @@ struct NativeFPL
|
|||
//FPL - Fixed Length Dynamic Memory Pool - every item has the same length
|
||||
struct FPL : public KernelObject
|
||||
{
|
||||
FPL() : blocks(NULL) {}
|
||||
~FPL() {
|
||||
if (blocks != NULL) {
|
||||
delete [] blocks;
|
||||
}
|
||||
}
|
||||
const char *GetName() {return nf.name;}
|
||||
const char *GetTypeName() {return "FPL";}
|
||||
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_FPLID; }
|
||||
|
@ -86,6 +92,8 @@ struct FPL : public KernelObject
|
|||
virtual void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(nf);
|
||||
if (p.mode == p.MODE_READ)
|
||||
blocks = new bool[nf.numBlocks];
|
||||
p.DoArray(blocks, nf.numBlocks);
|
||||
p.Do(address);
|
||||
p.DoMarker("FPL");
|
||||
|
@ -398,7 +406,7 @@ public:
|
|||
virtual void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(address);
|
||||
p.Do(name);
|
||||
p.DoArray(name, sizeof(name));
|
||||
p.DoMarker("PMB");
|
||||
}
|
||||
|
||||
|
@ -587,6 +595,53 @@ void sceKernelSetCompiledSdkVersion600_602(int sdkVersion)
|
|||
return;
|
||||
}
|
||||
|
||||
void sceKernelSetCompiledSdkVersion500_505(int sdkVersion)
|
||||
{
|
||||
int sdkMainVersion = sdkVersion & 0xFFFF0000;
|
||||
if(sdkMainVersion == 0x5000000
|
||||
|| sdkMainVersion == 0x5050000)
|
||||
{
|
||||
sdkVersion_ = sdkVersion;
|
||||
flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion500_505 unknown SDK : %x\n",sdkVersion);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void sceKernelSetCompiledSdkVersion401_402(int sdkVersion)
|
||||
{
|
||||
int sdkMainVersion = sdkVersion & 0xFFFF0000;
|
||||
if(sdkMainVersion == 0x4010000
|
||||
|| sdkMainVersion == 0x4020000)
|
||||
{
|
||||
sdkVersion_ = sdkVersion;
|
||||
flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion401_402 unknown SDK : %x\n",sdkVersion);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void sceKernelSetCompiledSdkVersion507(int sdkVersion)
|
||||
{
|
||||
int sdkMainVersion = sdkVersion & 0xFFFF0000;
|
||||
if(sdkMainVersion == 0x5070000)
|
||||
{
|
||||
sdkVersion_ = sdkVersion;
|
||||
flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion507 unknown SDK : %x\n",sdkVersion);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void sceKernelSetCompiledSdkVersion603_605(int sdkVersion)
|
||||
{
|
||||
int sdkMainVersion = sdkVersion & 0xFFFF0000;
|
||||
|
@ -877,7 +932,10 @@ const HLEFunction SysMemUserForUser[] = {
|
|||
{0x342061E5,&WrapV_I<sceKernelSetCompiledSdkVersion370>,"sceKernelSetCompiledSdkVersion370"},
|
||||
{0x315AD3A0,&WrapV_I<sceKernelSetCompiledSdkVersion380_390>,"sceKernelSetCompiledSdkVersion380_390"},
|
||||
{0xEBD5C3E6,&WrapV_I<sceKernelSetCompiledSdkVersion395>,"sceKernelSetCompiledSdkVersion395"},
|
||||
{0x057E7380,&WrapV_I<sceKernelSetCompiledSdkVersion401_402>,"sceKernelSetCompiledSdkVersion401_402"},
|
||||
{0xf77d77cb,&WrapV_I<sceKernelSetCompilerVersion>,"sceKernelSetCompilerVersion"},
|
||||
{0x91de343c,&WrapV_I<sceKernelSetCompiledSdkVersion500_505>,"sceKernelSetCompiledSdkVersion500_505"},
|
||||
{0x7893f79a,&WrapV_I<sceKernelSetCompiledSdkVersion507>,"sceKernelSetCompiledSdkVersion507"},
|
||||
{0x35669d4c,&WrapV_I<sceKernelSetCompiledSdkVersion600_602>,"sceKernelSetCompiledSdkVersion600_602"}, //??
|
||||
{0x1b4217bc,&WrapV_I<sceKernelSetCompiledSdkVersion603_605>,"sceKernelSetCompiledSdkVersion603_605"},
|
||||
{0x358ca1bb,&WrapV_I<sceKernelSetCompiledSdkVersion606>,"sceKernelSetCompiledSdkVersion606"},
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "sceKernelModule.h"
|
||||
#include "sceKernelThread.h"
|
||||
#include "sceKernelMemory.h"
|
||||
#include "sceIo.h"
|
||||
|
||||
enum {
|
||||
PSP_THREAD_ATTR_USER = 0x80000000
|
||||
|
@ -100,7 +101,7 @@ struct NativeModule {
|
|||
class Module : public KernelObject
|
||||
{
|
||||
public:
|
||||
Module() : memoryBlockAddr(0) {}
|
||||
Module() : memoryBlockAddr(0), isFake(false) {}
|
||||
~Module() {
|
||||
if (memoryBlockAddr) {
|
||||
userMemory.Free(memoryBlockAddr);
|
||||
|
@ -111,7 +112,8 @@ public:
|
|||
void GetQuickInfo(char *ptr, int size)
|
||||
{
|
||||
// ignore size
|
||||
sprintf(ptr, "name=%s gp=%08x entry=%08x",
|
||||
sprintf(ptr, "%sname=%s gp=%08x entry=%08x",
|
||||
isFake ? "faked " : "",
|
||||
nm.name,
|
||||
nm.gp_value,
|
||||
nm.entry_addr);
|
||||
|
@ -129,6 +131,7 @@ public:
|
|||
NativeModule nm;
|
||||
|
||||
u32 memoryBlockAddr;
|
||||
bool isFake;
|
||||
};
|
||||
|
||||
KernelObject *__KernelModuleObject()
|
||||
|
@ -212,6 +215,10 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
|||
kernelObjects.Create(module);
|
||||
|
||||
u8 *newptr = 0;
|
||||
if (*(u32*)ptr == 0x4543537e) { // "~SCE"
|
||||
INFO_LOG(HLE, "~SCE module, skipping header");
|
||||
ptr += *(u32*)(ptr + 4);
|
||||
}
|
||||
|
||||
if (*(u32*)ptr == 0x5053507e) { // "~PSP"
|
||||
// Decrypt module! YAY!
|
||||
|
@ -225,20 +232,23 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
|||
}
|
||||
newptr = new u8[head->elf_size + head->psp_size];
|
||||
ptr = newptr;
|
||||
pspDecryptPRX(in, (u8*)ptr, head->psp_size);
|
||||
int ret = pspDecryptPRX(in, (u8*)ptr, head->psp_size);
|
||||
if (ret == MISSING_KEY)
|
||||
{
|
||||
*error_string = "Missing key";
|
||||
delete [] newptr;
|
||||
module->isFake = true;
|
||||
strncpy(module->nm.name, head->modname, 28);
|
||||
module->nm.entry_addr = -1;
|
||||
module->nm.gp_value = -1;
|
||||
return module;
|
||||
}
|
||||
else if (ret <= 0)
|
||||
{
|
||||
ERROR_LOG(HLE, "Failed decrypting PRX! That's not normal!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (*(u32*)ptr == 0x4543537e) { // "~SCE"
|
||||
ERROR_LOG(HLE, "Wrong magic number %08x (~SCE, kernel module?)",*(u32*)ptr);
|
||||
*error_string = "Kernel module?";
|
||||
if (newptr)
|
||||
{
|
||||
delete [] newptr;
|
||||
}
|
||||
kernelObjects.Destroy<Module>(module->GetUID());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*(u32*)ptr != 0x464c457f)
|
||||
{
|
||||
ERROR_LOG(HLE, "Wrong magic number %08x",*(u32*)ptr);
|
||||
|
@ -297,6 +307,9 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
|||
else
|
||||
modinfo = (PspModuleInfo *)Memory::GetPointer(reader.GetSegmentVaddr(0) + (reader.GetSegmentPaddr(0) & 0x7FFFFFFF) - reader.GetSegmentOffset(0));
|
||||
|
||||
module->nm.gp_value = modinfo->gp;
|
||||
strncpy(module->nm.name, modinfo->name, 28);
|
||||
|
||||
// Check for module blacklist - we don't allow games to load these modules from disc
|
||||
// as we have HLE implementations and the originals won't run in the emu because they
|
||||
// directly access hardware or for other reasons.
|
||||
|
@ -307,8 +320,9 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
|||
{
|
||||
delete [] newptr;
|
||||
}
|
||||
kernelObjects.Destroy<Module>(module->GetUID());
|
||||
return 0;
|
||||
module->isFake = true;
|
||||
module->nm.entry_addr = -1;
|
||||
return module;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,9 +351,6 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
|||
}
|
||||
}
|
||||
|
||||
module->nm.gp_value = modinfo->gp;
|
||||
strncpy(module->nm.name, modinfo->name, 28);
|
||||
|
||||
INFO_LOG(LOADER,"Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent,modinfo->libstub);
|
||||
|
||||
struct PspLibStubEntry
|
||||
|
@ -688,9 +699,6 @@ u32 sceKernelLoadModule(const char *name, u32 flags)
|
|||
|
||||
void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, u32 optionAddr)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)",
|
||||
moduleId,argsize,argAddr,returnValueAddr,optionAddr);
|
||||
|
||||
// Dunno what these three defaults should be...
|
||||
u32 priority = 0x20;
|
||||
u32 stacksize = 0x40000;
|
||||
|
@ -707,12 +715,15 @@ void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValu
|
|||
u32 error;
|
||||
Module *module = kernelObjects.Get<Module>(moduleId, error);
|
||||
if (!module) {
|
||||
// TODO: Try not to lie so much.
|
||||
/*
|
||||
RETURN(error);
|
||||
return;
|
||||
*/
|
||||
} else if (module->isFake) {
|
||||
INFO_LOG(HLE,"sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): faked (undecryptable module)",
|
||||
moduleId,argsize,argAddr,returnValueAddr,optionAddr);
|
||||
} else {
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)",
|
||||
moduleId,argsize,argAddr,returnValueAddr,optionAddr);
|
||||
|
||||
u32 entryAddr = module->nm.entry_addr;
|
||||
if (entryAddr == -1) {
|
||||
entryAddr = module->nm.module_start_func;
|
||||
|
@ -785,10 +796,44 @@ void sceKernelFindModuleByName()
|
|||
RETURN(1);
|
||||
}
|
||||
|
||||
u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) {
|
||||
ERROR_LOG(HLE,"UNIMPL %008x=sceKernelLoadModuleById(%08x, %08x)",id,id,lmoptionPtr);
|
||||
// Apparenty, ID is a sceIo File UID. So this shouldn't be too hard when needed.
|
||||
return id;
|
||||
u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr)
|
||||
{
|
||||
u32 error;
|
||||
u32 handle = __IoGetFileHandleFromId(id, error);
|
||||
if (handle < 0) {
|
||||
ERROR_LOG(HLE,"sceKernelLoadModuleByID(%08x, %08x, %08x): could not open file id",id,flags,lmoptionPtr);
|
||||
return error;
|
||||
}
|
||||
SceKernelLMOption *lmoption = 0;
|
||||
if (lmoptionPtr) {
|
||||
lmoption = (SceKernelLMOption *)Memory::GetPointer(lmoptionPtr);
|
||||
}
|
||||
u32 pos = pspFileSystem.SeekFile(handle, 0, FILEMOVE_CURRENT);
|
||||
u32 size = pspFileSystem.SeekFile(handle, 0, FILEMOVE_END);
|
||||
std::string error_string;
|
||||
pspFileSystem.SeekFile(handle, pos, FILEMOVE_BEGIN);
|
||||
Module *module = 0;
|
||||
u8 *temp = new u8[size];
|
||||
pspFileSystem.ReadFile(handle, temp, size);
|
||||
module = __KernelLoadELFFromPtr(temp, 0, &error_string);
|
||||
delete [] temp;
|
||||
|
||||
if (!module) {
|
||||
// Module was blacklisted or couldn't be decrypted, which means it's a kernel module we don't want to run.
|
||||
// Let's just act as if it worked.
|
||||
NOTICE_LOG(LOADER, "Module %d is blacklisted or undecryptable - we lie about success", id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lmoption) {
|
||||
INFO_LOG(HLE,"%i=sceKernelLoadModuleByID(%d,flag=%08x,%08x,%08x,%08x,position = %08x)",
|
||||
module->GetUID(),id,flags,
|
||||
lmoption->size,lmoption->mpidtext,lmoption->mpiddata,lmoption->position);
|
||||
} else {
|
||||
INFO_LOG(HLE,"%i=sceKernelLoadModuleByID(%d,flag=%08x,(...))", module->GetUID(), id, flags);
|
||||
}
|
||||
|
||||
return module->GetUID();
|
||||
}
|
||||
|
||||
u32 sceKernelLoadModuleDNAS(const char *name, u32 flags)
|
||||
|
|
|
@ -456,7 +456,10 @@ int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr)
|
|||
return error;
|
||||
else
|
||||
{
|
||||
mutex->waitingThreads.push_back(__KernelGetCurThread());
|
||||
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);
|
||||
|
||||
|
@ -481,7 +484,10 @@ int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr)
|
|||
return error;
|
||||
else
|
||||
{
|
||||
mutex->waitingThreads.push_back(__KernelGetCurThread());
|
||||
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, true);
|
||||
|
||||
|
@ -813,7 +819,10 @@ int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr)
|
|||
LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea.uid, error);
|
||||
if (mutex)
|
||||
{
|
||||
mutex->waitingThreads.push_back(__KernelGetCurThread());
|
||||
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);
|
||||
__KernelWaitLwMutex(mutex, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, false);
|
||||
|
||||
|
@ -846,7 +855,10 @@ int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr)
|
|||
LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea.uid, error);
|
||||
if (mutex)
|
||||
{
|
||||
mutex->waitingThreads.push_back(__KernelGetCurThread());
|
||||
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);
|
||||
__KernelWaitLwMutex(mutex, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, true);
|
||||
|
||||
|
|
|
@ -360,7 +360,11 @@ int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *bad
|
|||
else
|
||||
{
|
||||
s->ns.numWaitThreads++;
|
||||
s->waitingThreads.push_back(__KernelGetCurThread());
|
||||
|
||||
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(s->waitingThreads.begin(), s->waitingThreads.end(), threadID) == s->waitingThreads.end())
|
||||
s->waitingThreads.push_back(threadID);
|
||||
__KernelSetSemaTimeout(s, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, timeoutPtr, processCallbacks);
|
||||
}
|
||||
|
|
|
@ -75,11 +75,6 @@ const char *waitTypeStrings[] = {
|
|||
"Ctrl",
|
||||
};
|
||||
|
||||
struct SceKernelSysClock {
|
||||
u32 low;
|
||||
u32 hi;
|
||||
};
|
||||
|
||||
struct NativeCallback
|
||||
{
|
||||
SceUInt size;
|
||||
|
@ -371,11 +366,19 @@ public:
|
|||
// Fill the stack.
|
||||
Memory::Memset(stackBlock, 0xFF, stackSize);
|
||||
context.r[MIPS_REG_SP] = stackBlock + stackSize;
|
||||
nt.initialStack = context.r[MIPS_REG_SP];
|
||||
nt.initialStack = stackBlock;
|
||||
nt.stackSize = stackSize;
|
||||
// What's this 512?
|
||||
context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP] - 512;
|
||||
context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP] - 256;
|
||||
context.r[MIPS_REG_SP] -= 512;
|
||||
u32 k0 = context.r[MIPS_REG_K0];
|
||||
Memory::Memset(k0, 0, 0x100);
|
||||
Memory::Write_U32(nt.initialStack, k0 + 0xc0);
|
||||
Memory::Write_U32(GetUID(), k0 + 0xca);
|
||||
Memory::Write_U32(0xffffffff, k0 + 0xf8);
|
||||
Memory::Write_U32(0xffffffff, k0 + 0xfc);
|
||||
|
||||
Memory::Write_U32(GetUID(), nt.initialStack);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1145,9 +1148,15 @@ void sceKernelCheckThreadStack()
|
|||
{
|
||||
u32 error;
|
||||
Thread *t = kernelObjects.Get<Thread>(__KernelGetCurThread(), error);
|
||||
u32 diff = abs((long)((s64)t->stackBlock - (s64)currentMIPS->r[MIPS_REG_SP]));
|
||||
ERROR_LOG(HLE, "%i=sceKernelCheckThreadStack()", diff);
|
||||
RETURN(diff); //Blatant lie
|
||||
if (t) {
|
||||
u32 diff = abs((long)((s64)t->stackBlock - (s64)currentMIPS->r[MIPS_REG_SP]));
|
||||
WARN_LOG(HLE, "%i=sceKernelCheckThreadStack()", diff);
|
||||
RETURN(diff);
|
||||
} else {
|
||||
// WTF?
|
||||
ERROR_LOG(HLE, "sceKernelCheckThreadStack() - not on thread");
|
||||
RETURN(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadContext::reset()
|
||||
|
@ -1225,7 +1234,7 @@ Thread *__KernelCreateThread(SceUID &id, SceUID moduleId, const char *name, u32
|
|||
t->nt.numInterruptPreempts = 0;
|
||||
t->nt.numReleases = 0;
|
||||
t->nt.numThreadPreempts = 0;
|
||||
t->nt.runForClocks.low = 0;
|
||||
t->nt.runForClocks.lo = 0;
|
||||
t->nt.runForClocks.hi = 0;
|
||||
t->nt.wakeupCount = 0;
|
||||
if (moduleId)
|
||||
|
|
|
@ -54,6 +54,11 @@ void sceKernelGetThreadExitStatus();
|
|||
u32 sceKernelGetThreadmanIdType(u32);
|
||||
u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 idCountPtr);
|
||||
|
||||
struct SceKernelSysClock {
|
||||
u32 lo;
|
||||
u32 hi;
|
||||
};
|
||||
|
||||
|
||||
enum WaitType //probably not the real values
|
||||
{
|
||||
|
@ -79,19 +84,19 @@ enum WaitType //probably not the real values
|
|||
|
||||
struct ThreadContext
|
||||
{
|
||||
void reset();
|
||||
u32 r[32];
|
||||
float f[32];
|
||||
float v[128];
|
||||
u32 vfpuCtrl[16];
|
||||
void reset();
|
||||
u32 r[32];
|
||||
float f[32];
|
||||
float v[128];
|
||||
u32 vfpuCtrl[16];
|
||||
|
||||
u32 hi;
|
||||
u32 lo;
|
||||
u32 pc;
|
||||
u32 fpcond;
|
||||
u32 hi;
|
||||
u32 lo;
|
||||
u32 pc;
|
||||
u32 fpcond;
|
||||
|
||||
u32 fcr0;
|
||||
u32 fcr31;
|
||||
u32 fcr0;
|
||||
u32 fcr31;
|
||||
};
|
||||
|
||||
// Internal API, used by implementations of kernel functions
|
||||
|
@ -126,15 +131,15 @@ void __KernelReSchedule(bool doCallbacks, const char *reason);
|
|||
|
||||
// Registered callback types
|
||||
enum RegisteredCallbackType {
|
||||
THREAD_CALLBACK_UMD = 0,
|
||||
THREAD_CALLBACK_IO = 1,
|
||||
THREAD_CALLBACK_MEMORYSTICK = 2,
|
||||
THREAD_CALLBACK_MEMORYSTICK_FAT = 3,
|
||||
THREAD_CALLBACK_POWER = 4,
|
||||
THREAD_CALLBACK_EXIT = 5,
|
||||
THREAD_CALLBACK_USER_DEFINED = 6,
|
||||
THREAD_CALLBACK_SIZE = 7,
|
||||
THREAD_CALLBACK_NUM_TYPES = 8,
|
||||
THREAD_CALLBACK_UMD = 0,
|
||||
THREAD_CALLBACK_IO = 1,
|
||||
THREAD_CALLBACK_MEMORYSTICK = 2,
|
||||
THREAD_CALLBACK_MEMORYSTICK_FAT = 3,
|
||||
THREAD_CALLBACK_POWER = 4,
|
||||
THREAD_CALLBACK_EXIT = 5,
|
||||
THREAD_CALLBACK_USER_DEFINED = 6,
|
||||
THREAD_CALLBACK_SIZE = 7,
|
||||
THREAD_CALLBACK_NUM_TYPES = 8,
|
||||
};
|
||||
|
||||
// These operate on the current thread
|
||||
|
@ -214,6 +219,7 @@ struct MipsCall {
|
|||
|
||||
void DoState(PointerWrap &p);
|
||||
};
|
||||
|
||||
enum ThreadStatus
|
||||
{
|
||||
THREADSTATUS_RUNNING = 1,
|
||||
|
|
|
@ -30,10 +30,28 @@
|
|||
|
||||
#include "../CoreTiming.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// State
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The time when the game started.
|
||||
time_t start_time;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Other clock stuff
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void __KernelTimeInit()
|
||||
{
|
||||
time(&start_time);
|
||||
}
|
||||
|
||||
void __KernelTimeDoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(start_time);
|
||||
p.DoMarker("sceKernelTime");
|
||||
}
|
||||
|
||||
struct SceKernelSysClock
|
||||
{
|
||||
u32 lo;
|
||||
|
@ -107,19 +125,23 @@ u32 sceKernelUSec2SysClockWide(u32 usec)
|
|||
|
||||
u32 sceKernelLibcClock()
|
||||
{
|
||||
u32 retVal = clock()*1000; // TODO: This can't be right
|
||||
DEBUG_LOG(HLE,"%i = sceKernelLibcClock",retVal);
|
||||
u32 retVal = (u32) (CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz());
|
||||
DEBUG_LOG(HLE, "%i = sceKernelLibcClock", retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void sceKernelLibcTime()
|
||||
u32 sceKernelLibcTime(u32 outPtr)
|
||||
{
|
||||
time_t *t = 0;
|
||||
if (PARAM(0))
|
||||
t = (time_t*)Memory::GetPointer(PARAM(0));
|
||||
u32 retVal = (u32)time(t);
|
||||
DEBUG_LOG(HLE,"%i = sceKernelLibcTime()",retVal);
|
||||
RETURN(retVal);
|
||||
u32 t = (u32) start_time + (u32) (CoreTiming::GetTicks() / CPU_HZ);
|
||||
|
||||
DEBUG_LOG(HLE, "%i = sceKernelLibcTime(%08X)", t, outPtr);
|
||||
|
||||
if (Memory::IsValidAddress(outPtr))
|
||||
Memory::Write_U32(t, outPtr);
|
||||
else if (outPtr != 0)
|
||||
return 0;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void sceKernelLibcGettimeofday()
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#pragma once
|
||||
|
||||
void sceKernelLibcGettimeofday();
|
||||
void sceKernelLibcTime();
|
||||
u32 sceKernelLibcTime(u32 outPtr);
|
||||
void sceKernelUSec2SysClock();
|
||||
void sceKernelGetSystemTime();
|
||||
void sceKernelGetSystemTimeLow();
|
||||
|
@ -27,3 +27,6 @@ void sceKernelSysClock2USec();
|
|||
void sceKernelSysClock2USecWide();
|
||||
u32 sceKernelUSec2SysClockWide(u32 usec);
|
||||
u32 sceKernelLibcClock();
|
||||
|
||||
void __KernelTimeInit();
|
||||
void __KernelTimeDoState(PointerWrap &p);
|
||||
|
|
|
@ -16,77 +16,224 @@
|
|||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelThread.h"
|
||||
#include "sceKernelVTimer.h"
|
||||
#include "HLE.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// VTIMER
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Using ERROR_LOG liberally when this is in development. When done,
|
||||
// should be changed to DEBUG_LOG wherever applicable.
|
||||
|
||||
struct VTimer : public KernelObject
|
||||
{
|
||||
const char *GetName() {return name;}
|
||||
struct NativeVTimer {
|
||||
SceSize size;
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
|
||||
int running;
|
||||
SceKernelSysClock basetime;
|
||||
SceKernelSysClock curtime;
|
||||
SceKernelSysClock scheduletime;
|
||||
u32 handlerAddr;
|
||||
u32 argument;
|
||||
};
|
||||
|
||||
struct VTimer : public KernelObject {
|
||||
const char *GetName() {return nvt.name;}
|
||||
const char *GetTypeName() {return "VTimer";}
|
||||
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_VTID; }
|
||||
int GetIDType() const { return SCE_KERNEL_TMID_VTimer; }
|
||||
|
||||
virtual void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(size);
|
||||
p.Do(name);
|
||||
p.Do(startTime);
|
||||
p.Do(running);
|
||||
p.Do(handler);
|
||||
p.Do(handlerTime);
|
||||
p.Do(argument);
|
||||
virtual void DoState(PointerWrap &p) {
|
||||
p.Do(nvt);
|
||||
p.DoMarker("VTimer");
|
||||
}
|
||||
|
||||
SceSize size;
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
|
||||
u64 startTime;
|
||||
bool running;
|
||||
u32 handler;
|
||||
u64 handlerTime;
|
||||
u32 argument;
|
||||
NativeVTimer nvt;
|
||||
};
|
||||
|
||||
KernelObject *__KernelVTimerObject()
|
||||
{
|
||||
KernelObject *__KernelVTimerObject() {
|
||||
return new VTimer;
|
||||
}
|
||||
|
||||
void sceKernelCreateVTimer()
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelCreateVTimer");
|
||||
const char *name = Memory::GetCharPointer(PARAM(0));
|
||||
u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr) {
|
||||
ERROR_LOG(HLE,"FAKE sceKernelCreateVTimer(%s, %08x)", name, optParamAddr);
|
||||
|
||||
VTimer *vt = new VTimer();
|
||||
|
||||
SceUID uid = kernelObjects.Create(vt);
|
||||
strncpy(vt->name, name, 32);
|
||||
vt->running = true;
|
||||
vt->startTime = 0; //TODO fix
|
||||
RETURN(uid); //TODO: return timer ID
|
||||
memset(&vt->nvt, 0, sizeof(vt->nvt));
|
||||
if (name)
|
||||
strncpy(vt->nvt.name, name, 32);
|
||||
vt->nvt.running = 1;
|
||||
return uid; //TODO: return timer ID
|
||||
}
|
||||
|
||||
void sceKernelStartVTimer()
|
||||
{
|
||||
int timerID = PARAM(0);
|
||||
DEBUG_LOG(HLE,"sceKernelStartVTimer(%i)", timerID);
|
||||
u32 sceKernelDeleteVTimer(u32 uid) {
|
||||
ERROR_LOG(HLE,"FAKE sceKernelDeleteVTimer(%i)", uid);
|
||||
|
||||
RETURN(0); //ok; 1=alreadyrunning
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
// TODO: Deschedule events here. Might share code with Stop.
|
||||
|
||||
return kernelObjects.Destroy<VTimer>(uid);
|
||||
}
|
||||
|
||||
void sceKernelSetVTimerHandler()
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelSetVTimerHandler");
|
||||
u32 sceKernelStartVTimer(u32 uid) {
|
||||
ERROR_LOG(HLE,"FAKE sceKernelStartVTimer(%i)", uid);
|
||||
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
if (vt->nvt.running) {
|
||||
// Already running
|
||||
return 1;
|
||||
} else {
|
||||
vt->nvt.running = 1;
|
||||
// TODO: Schedule events etc.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 sceKernelStopVTimer(u32 uid) {
|
||||
ERROR_LOG(HLE,"FAKE sceKernelStartVTimer(%i)", uid);
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
if (vt->nvt.running) {
|
||||
// Already running
|
||||
return 0;
|
||||
} else {
|
||||
vt->nvt.running = 0;
|
||||
// TODO: Deschedule events etc.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
u32 sceKernelSetVTimerHandler(u32 uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr) {
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelSetVTimerHandler(%i, %08x, %08x, %08x)",
|
||||
uid, scheduleAddr, handlerFuncAddr, commonAddr);
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceKernelSetVTimerHandlerWide(u32 uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr) {
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelSetVTimerHandlerWide(%i, %llu, %08x, %08x)",
|
||||
uid, schedule, handlerFuncAddr, commonAddr);
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceKernelCancelVTimerHandler(u32 uid) {
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelCancelVTimerHandler(%i)", uid);
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceKernelReferVTimerStatus(u32 uid, u32 statusAddr) {
|
||||
ERROR_LOG(HLE,"sceKernelReferVTimerStatus(%i, %08x)", uid, statusAddr);
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
// TODO: possibly update time values here?
|
||||
Memory::WriteStruct(statusAddr, &vt->nvt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceKernelGetVTimerBase(u32 uid, u32 baseClockAddr) {
|
||||
ERROR_LOG(HLE,"sceKernelGetVTimerBase(%i, %08x)", uid, baseClockAddr);
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
Memory::WriteStruct(baseClockAddr, &vt->nvt.basetime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 sceKernelGetVTimerBaseWide(u32 uid) {
|
||||
ERROR_LOG(HLE,"sceKernelGetVTimerWide(%i)", uid);
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
// TODO: probably update the timer somehow?
|
||||
u64 t = vt->nvt.curtime.lo;
|
||||
t |= (u64)(vt->nvt.curtime.hi) << 32;
|
||||
return t;
|
||||
}
|
||||
|
||||
u32 sceKernelGetVTimerTime(u32 uid, u32 timeClockAddr) {
|
||||
ERROR_LOG(HLE,"sceKernelGetVTimerTime(%i, %08x)", uid, timeClockAddr);
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
// TODO: probably update the timer somehow?
|
||||
Memory::WriteStruct(timeClockAddr, &vt->nvt.curtime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 sceKernelGetVTimerTimeWide(u32 uid) {
|
||||
ERROR_LOG(HLE,"sceKernelGetVTimerTimeWide(%i)", uid);
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
// TODO: probably update the timer somehow?
|
||||
u64 t = vt->nvt.curtime.lo;
|
||||
t |= (u64)(vt->nvt.curtime.hi) << 32;
|
||||
return t;
|
||||
}
|
||||
|
||||
u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr) {
|
||||
ERROR_LOG(HLE,"sceKernelSetVTimerTime(%i, %08x)", uid, timeClockAddr);
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
Memory::ReadStruct(timeClockAddr, &vt->nvt.curtime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceKernelSetVTimerTimeWide(u32 uid, u64 timeClock) {
|
||||
ERROR_LOG(HLE,"sceKernelSetVTimerTime(%i, %llu)", uid, timeClock);
|
||||
u32 error;
|
||||
VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
|
||||
if (!vt) {
|
||||
return error;
|
||||
}
|
||||
vt->nvt.curtime.lo = timeClock & 0xFFFFFFFF;
|
||||
vt->nvt.curtime.hi = timeClock >> 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Not sure why this is exposed...
|
||||
void _sceKernelReturnFromTimerHandler()
|
||||
{
|
||||
DEBUG_LOG(HLE,"_sceKernelReturnFromTimerHandler");
|
||||
|
||||
ERROR_LOG(HLE,"_sceKernelReturnFromTimerHandler - should not be called!");
|
||||
}
|
||||
|
|
|
@ -17,9 +17,20 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
void sceKernelCreateVTimer();
|
||||
void sceKernelStartVTimer();
|
||||
void sceKernelSetVTimerHandler();
|
||||
u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr);
|
||||
u32 sceKernelDeleteVTimer(u32 uid);
|
||||
u32 sceKernelStartVTimer(u32 uid);
|
||||
u32 sceKernelStopVTimer(u32 uid);
|
||||
u32 sceKernelSetVTimerHandler(u32 uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr);
|
||||
u32 sceKernelSetVTimerHandlerWide(u32 uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr);
|
||||
u32 sceKernelCancelVTimerHandler(u32 uid);
|
||||
u32 sceKernelReferVTimerStatus(u32 uid, u32 statusAddr);
|
||||
u32 sceKernelGetVTimerBase(u32 uid, u32 baseClockAddr); //SceKernelSysClock
|
||||
u64 sceKernelGetVTimerBaseWide(u32 uid);
|
||||
u32 sceKernelGetVTimerTime(u32 uid, u32 timeClockAddr);
|
||||
u64 sceKernelGetVTimerTimeWide(u32 uid);
|
||||
u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr);
|
||||
u32 sceKernelSetVTimerTimeWide(u32 uid, u64 timeClock);
|
||||
|
||||
// TODO
|
||||
void _sceKernelReturnFromTimerHandler();
|
||||
|
|
|
@ -181,7 +181,7 @@ u32 scePowerSetBusClockFrequency(u32 busfreq) {
|
|||
|
||||
u32 scePowerGetCpuClockFrequencyInt() {
|
||||
int freq = CoreTiming::GetClockFrequencyMHz();
|
||||
INFO_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", freq);
|
||||
DEBUG_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", freq);
|
||||
return freq;
|
||||
}
|
||||
|
||||
|
|
|
@ -226,17 +226,19 @@ u32 sceSasSetKeyOn(u32 core, int voiceNum)
|
|||
// sceSasSetKeyOff can be used to start sounds, that just sound during the Release phase!
|
||||
u32 sceSasSetKeyOff(u32 core, int voiceNum)
|
||||
{
|
||||
DEBUG_LOG(HLE,"0=sceSasSetKeyOff(core=%08x, voiceNum=%i)", core, voiceNum);
|
||||
|
||||
if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0)
|
||||
{
|
||||
if (voiceNum == -1) {
|
||||
// TODO: Some games (like Every Extend Extra) deliberately pass voiceNum = -1. Does that mean all voices? for now let's ignore.
|
||||
DEBUG_LOG(HLE,"sceSasSetKeyOff(core=%08x, voiceNum=%i) - voiceNum = -1???", core, voiceNum);
|
||||
return 0;
|
||||
} else if (voiceNum < 0 || voiceNum >= PSP_SAS_VOICES_MAX) {
|
||||
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
||||
return ERROR_SAS_INVALID_VOICE;
|
||||
} else {
|
||||
DEBUG_LOG(HLE,"0=sceSasSetKeyOff(core=%08x, voiceNum=%i)", core, voiceNum);
|
||||
SasVoice &v = sas->voices[voiceNum];
|
||||
v.KeyOff();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SasVoice &v = sas->voices[voiceNum];
|
||||
v.KeyOff();
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceSasSetNoise(u32 core, int voiceNum, int freq)
|
||||
|
|
|
@ -88,20 +88,32 @@ int sceUtilitySavedataUpdate(int animSpeed)
|
|||
#define PSP_AV_MODULE_AAC 6
|
||||
#define PSP_AV_MODULE_G729 7
|
||||
|
||||
//TODO: Shouldn't be void
|
||||
void sceUtilityLoadAvModule(u32 module)
|
||||
u32 sceUtilityLoadAvModule(u32 module)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceUtilityLoadAvModule(%i)", module);
|
||||
RETURN(0);
|
||||
__KernelReSchedule("utilityloadavmodule");
|
||||
hleReSchedule("utilityloadavmodule");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//TODO: Shouldn't be void
|
||||
void sceUtilityLoadModule(u32 module)
|
||||
u32 sceUtilityUnloadAvModule(u32 module)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceUtilityUnloadAvModule(%i)", module);
|
||||
hleReSchedule("utilityunloadavmodule");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceUtilityLoadModule(u32 module)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceUtilityLoadModule(%i)", module);
|
||||
RETURN(0);
|
||||
__KernelReSchedule("utilityloadmodule");
|
||||
hleReSchedule("utilityloadmodule");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceUtilityUnloadModule(u32 module)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceUtilityUnloadModule(%i)", module);
|
||||
hleReSchedule("utilityunloadmodule");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceUtilityMsgDialogInitStart(u32 structAddr)
|
||||
|
@ -406,11 +418,11 @@ const HLEFunction sceUtility[] =
|
|||
{0xf5ce1134, 0, "sceUtilityHtmlViewerShutdownStart"},
|
||||
{0x05afb9e4, 0, "sceUtilityHtmlViewerUpdate"},
|
||||
|
||||
{0xc629af26, &WrapV_U<sceUtilityLoadAvModule>, "sceUtilityLoadAvModule"},
|
||||
{0xf7d8d092, 0, "sceUtilityUnloadAvModule"},
|
||||
{0xc629af26, &WrapU_U<sceUtilityLoadAvModule>, "sceUtilityLoadAvModule"},
|
||||
{0xf7d8d092, &WrapU_U<sceUtilityUnloadAvModule>, "sceUtilityUnloadAvModule"},
|
||||
|
||||
{0x2a2b3de0, &WrapV_U<sceUtilityLoadModule>, "sceUtilityLoadModule"},
|
||||
{0xe49bfe92, 0, "sceUtilityUnloadModule"},
|
||||
{0x2a2b3de0, &WrapU_U<sceUtilityLoadModule>, "sceUtilityLoadModule"},
|
||||
{0xe49bfe92, &WrapU_U<sceUtilityUnloadModule>, "sceUtilityUnloadModule"},
|
||||
|
||||
{0x0251B134, 0, "sceUtilityScreenshotInitStart"},
|
||||
{0xF9E0008C, 0, "sceUtilityScreenshotShutdownStart"},
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
// 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 "HLE.h"
|
||||
|
||||
#include "scesupPreAcc.h"
|
||||
|
||||
const HLEFunction scesupPreAcc[] =
|
||||
{
|
||||
{0x110e318b, 0, "scesupPreAcc_0x110e318b"},
|
||||
{0x13ae25b3, 0, "scesupPreAcc_0x13ae25b3"},
|
||||
{0x28c5f696, 0, "scesupPreAcc_0x28c5f696"},
|
||||
{0x348ba3e2, 0, "scesupPreAcc_0x348ba3e2"},
|
||||
{0x86debd66, 0, "scesupPreAcc_0x86debd66"},
|
||||
{0xa0eaf444, 0, "scesupPreAcc_0xa0eaf444"},
|
||||
{0xb03ff882, 0, "scesupPreAcc_0xb03ff882"},
|
||||
{0x2ec3f4d9, 0, "scesupPreAcc_0x2ec3f4d9"},
|
||||
|
||||
};
|
||||
|
||||
void Register_scesupPreAcc()
|
||||
{
|
||||
RegisterModule("scesupPreAcc",ARRAY_SIZE(scesupPreAcc), scesupPreAcc );
|
||||
}
|
|
@ -60,6 +60,9 @@ public:
|
|||
virtual bool IsDebuggingEnabled() {return true;}
|
||||
virtual bool AttemptLoadSymbolMap() {return false;}
|
||||
virtual void SetWindowTitle(const char *message) {}
|
||||
|
||||
// Used for headless.
|
||||
virtual void SendDebugOutput(const std::string &output) {}
|
||||
};
|
||||
|
||||
extern Host *host;
|
||||
|
|
|
@ -42,6 +42,10 @@ namespace MIPSComp
|
|||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
int o = op>>26;
|
||||
if (((op >> 29) & 1) == 0 && rt == 0) {
|
||||
// Don't load anything into $zr
|
||||
return;
|
||||
}
|
||||
switch (o)
|
||||
{
|
||||
case 37: //R(rt) = ReadMem16(addr); break; //lhu
|
||||
|
|
|
@ -362,12 +362,8 @@ void JitBlockCache::DestroyBlock(int block_num, bool invalidate)
|
|||
return;
|
||||
}
|
||||
b.invalid = true;
|
||||
#ifdef JIT_UNLIMITED_ICACHE
|
||||
Memory::Write_Opcode_JIT(b.originalAddress, b.originalFirstOpcode?b.originalFirstOpcode:JIT_ICACHE_INVALID_WORD);
|
||||
#else
|
||||
if ((int)Memory::ReadUnchecked_U32(b.originalAddress) == block_num)
|
||||
if ((int)Memory::ReadUnchecked_U32(b.originalAddress) == (MIPS_EMUHACK_OPCODE | block_num))
|
||||
Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress);
|
||||
#endif
|
||||
|
||||
UnlinkBlock(block_num);
|
||||
|
||||
|
|
|
@ -301,8 +301,10 @@ namespace MIPSInt
|
|||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
|
||||
if (rt == 0) //destination register is zero register
|
||||
if (rt == 0) { //destination register is zero register
|
||||
PC += 4;
|
||||
return; //nop
|
||||
}
|
||||
|
||||
switch (op>>26)
|
||||
{
|
||||
|
@ -398,6 +400,12 @@ namespace MIPSInt
|
|||
int rs = _RS;
|
||||
u32 addr = R(rs) + imm;
|
||||
|
||||
if (((op >> 29) & 1) == 0 && rt == 0) {
|
||||
// Don't load anything into $zr
|
||||
PC += 4;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (op >> 26)
|
||||
{
|
||||
case 32: R(rt) = (u32)(s32)(s8) Memory::Read_U8(addr); break; //lb
|
||||
|
|
|
@ -62,7 +62,7 @@ void Jit()
|
|||
|
||||
void ImHere()
|
||||
{
|
||||
DEBUG_LOG(CPU, "I'm Here: %08x", currentMIPS->pc);
|
||||
DEBUG_LOG(CPU, "JIT Here: %08x", currentMIPS->pc);
|
||||
}
|
||||
|
||||
void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
|
||||
|
@ -107,7 +107,7 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
|
|||
dispatcherNoCheck = GetCodePtr();
|
||||
|
||||
// Debug
|
||||
//CALL(&ImHere);
|
||||
// CALL(&ImHere);
|
||||
|
||||
MOV(32, R(EAX), M(&mips->pc));
|
||||
#ifdef _M_IX86
|
||||
|
|
|
@ -52,6 +52,11 @@ namespace MIPSComp
|
|||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
int o = op>>26;
|
||||
if (((op >> 29) & 1) == 0 && rt == 0) {
|
||||
// Don't load anything into $zr
|
||||
return;
|
||||
}
|
||||
|
||||
switch (o)
|
||||
{
|
||||
case 37: //R(rt) = ReadMem16(addr); break; //lhu
|
||||
|
|
|
@ -88,6 +88,14 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b)
|
|||
js.compiling = true;
|
||||
js.inDelaySlot = false;
|
||||
|
||||
// We add a check before the block, used when entering from a linked block.
|
||||
b->checkedEntry = GetCodePtr();
|
||||
// Downcount flag check. The last block decremented downcounter, and the flag should still be available.
|
||||
FixupBranch skip = J_CC(CC_NBE);
|
||||
MOV(32, M(&mips_->pc), Imm32(js.blockStart));
|
||||
JMP(asm_.outerLoop, true); // downcount hit zero - go advance.
|
||||
SetJumpTarget(skip);
|
||||
|
||||
b->normalEntry = GetCodePtr();
|
||||
|
||||
// TODO: this needs work
|
||||
|
|
|
@ -347,12 +347,8 @@ void JitBlockCache::DestroyBlock(int block_num, bool invalidate)
|
|||
return;
|
||||
}
|
||||
b.invalid = true;
|
||||
#ifdef JIT_UNLIMITED_ICACHE
|
||||
Memory::Write_Opcode_JIT(b.originalAddress, b.originalFirstOpcode?b.originalFirstOpcode:JIT_ICACHE_INVALID_WORD);
|
||||
#else
|
||||
if (Memory::ReadUnchecked_U32(b.originalAddress) == (u32)block_num)
|
||||
if ((int)Memory::ReadUnchecked_U32(b.originalAddress) == (MIPS_EMUHACK_OPCODE | block_num))
|
||||
Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress);
|
||||
#endif
|
||||
|
||||
UnlinkBlock(block_num);
|
||||
|
||||
|
|
|
@ -77,11 +77,10 @@ bool Load_PSP_ISO(const char *filename, std::string *error_string)
|
|||
u32 fd = pspFileSystem.OpenFile(sfoPath, FILEACCESS_READ);
|
||||
pspFileSystem.ReadFile(fd, paramsfo, fileInfo.size);
|
||||
pspFileSystem.CloseFile(fd);
|
||||
ParamSFOData data;
|
||||
if (data.ReadSFO(paramsfo, (size_t)fileInfo.size))
|
||||
if (g_paramSFO.ReadSFO(paramsfo, (size_t)fileInfo.size))
|
||||
{
|
||||
char title[1024];
|
||||
sprintf(title, "%s : %s", data.GetValueString("DISC_ID").c_str(), data.GetValueString("TITLE").c_str());
|
||||
sprintf(title, "%s : %s", g_paramSFO.GetValueString("DISC_ID").c_str(), g_paramSFO.GetValueString("TITLE").c_str());
|
||||
INFO_LOG(LOADER, "%s", title);
|
||||
host->SetWindowTitle(title);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "../Common/StdMutex.h"
|
||||
#include "../Common/FileUtil.h"
|
||||
#include <vector>
|
||||
|
||||
#include "SaveState.h"
|
||||
|
@ -45,23 +46,24 @@ namespace SaveState
|
|||
|
||||
struct Operation
|
||||
{
|
||||
Operation(OperationType t, const std::string &f, Callback cb)
|
||||
: type(t), filename(f), callback(cb)
|
||||
Operation(OperationType t, const std::string &f, Callback cb, void *cbUserData_)
|
||||
: type(t), filename(f), callback(cb), cbUserData(cbUserData_)
|
||||
{
|
||||
}
|
||||
|
||||
OperationType type;
|
||||
std::string filename;
|
||||
Callback callback;
|
||||
void *cbUserData;
|
||||
};
|
||||
|
||||
static int timer;
|
||||
static bool needsProcess = false;
|
||||
static std::vector<Operation> pending;
|
||||
static std::recursive_mutex mutex;
|
||||
|
||||
void Process(u64 userdata, int cyclesLate);
|
||||
|
||||
// This is where the magic happens.
|
||||
void SaveStart::DoState(PointerWrap &p)
|
||||
{
|
||||
// Gotta do CoreTiming first since we'll restore into it.
|
||||
|
@ -87,28 +89,105 @@ namespace SaveState
|
|||
|
||||
// Don't actually run it until next CoreTiming::Advance().
|
||||
// It's possible there might be a duplicate but it won't hurt us.
|
||||
if (Core_IsStepping())
|
||||
if (Core_IsStepping() && __KernelIsRunning())
|
||||
{
|
||||
// Warning: this may run on a different thread.
|
||||
Process(0, 0);
|
||||
}
|
||||
else
|
||||
else if (__KernelIsRunning())
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, timer);
|
||||
else
|
||||
needsProcess = true;
|
||||
}
|
||||
|
||||
void Load(const std::string &filename, Callback callback)
|
||||
void Load(const std::string &filename, Callback callback, void *cbUserData)
|
||||
{
|
||||
Enqueue(Operation(SAVESTATE_LOAD, filename, callback));
|
||||
Enqueue(Operation(SAVESTATE_LOAD, filename, callback, cbUserData));
|
||||
}
|
||||
|
||||
void Save(const std::string &filename, Callback callback)
|
||||
void Save(const std::string &filename, Callback callback, void *cbUserData)
|
||||
{
|
||||
Enqueue(Operation(SAVESTATE_SAVE, filename, callback));
|
||||
Enqueue(Operation(SAVESTATE_SAVE, filename, callback, cbUserData));
|
||||
}
|
||||
|
||||
void Verify(Callback callback)
|
||||
|
||||
// Slot utilities
|
||||
|
||||
std::string GenerateSaveSlotFilename(int slot)
|
||||
{
|
||||
Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback));
|
||||
char discID[256];
|
||||
char temp[256];
|
||||
sprintf(discID, "%s_%s",
|
||||
g_paramSFO.GetValueString("DISC_ID").c_str(),
|
||||
g_paramSFO.GetValueString("DISC_VERSION").c_str());
|
||||
sprintf(temp, "ms0:/PSP/PPSSPP_STATE/%s_%i.ppst", discID, slot);
|
||||
std::string hostPath;
|
||||
if (pspFileSystem.GetHostPath(std::string(temp), hostPath)) {
|
||||
return hostPath;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void LoadSlot(int slot, Callback callback, void *cbUserData)
|
||||
{
|
||||
std::string fn = GenerateSaveSlotFilename(slot);
|
||||
if (!fn.empty())
|
||||
Load(fn, callback, cbUserData);
|
||||
else
|
||||
(*callback)(false, cbUserData);
|
||||
}
|
||||
|
||||
void SaveSlot(int slot, Callback callback, void *cbUserData)
|
||||
{
|
||||
std::string fn = GenerateSaveSlotFilename(slot);
|
||||
if (!fn.empty())
|
||||
Save(fn, callback, cbUserData);
|
||||
else
|
||||
(*callback)(false, cbUserData);
|
||||
}
|
||||
|
||||
void HasSaveInSlot(int slot)
|
||||
{
|
||||
std::string fn = GenerateSaveSlotFilename(slot);
|
||||
}
|
||||
|
||||
bool operator < (const tm &t1, const tm &t2) {
|
||||
if (t1.tm_year < t2.tm_year) return true;
|
||||
if (t1.tm_year > t2.tm_year) return false;
|
||||
if (t1.tm_mon < t2.tm_mon) return true;
|
||||
if (t1.tm_mon > t2.tm_mon) return false;
|
||||
if (t1.tm_mday < t2.tm_mday) return true;
|
||||
if (t1.tm_mday > t2.tm_mday) return false;
|
||||
if (t1.tm_hour < t2.tm_hour) return true;
|
||||
if (t1.tm_hour > t2.tm_hour) return false;
|
||||
if (t1.tm_min < t2.tm_min) return true;
|
||||
if (t1.tm_min > t2.tm_min) return false;
|
||||
if (t1.tm_sec < t2.tm_sec) return true;
|
||||
if (t1.tm_sec > t2.tm_sec) return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetMostRecentSaveSlot() {
|
||||
int newestSlot = -1;
|
||||
tm newestDate = {0};
|
||||
for (int i = 0; i < SAVESTATESLOTS; i++) {
|
||||
std::string fn = GenerateSaveSlotFilename(i);
|
||||
if (File::Exists(fn)) {
|
||||
tm time = File::GetModifTime(fn);
|
||||
if (newestDate < time) {
|
||||
newestDate = time;
|
||||
newestSlot = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newestSlot;
|
||||
}
|
||||
|
||||
|
||||
void Verify(Callback callback, void *cbUserData)
|
||||
{
|
||||
Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback, cbUserData));
|
||||
}
|
||||
|
||||
std::vector<Operation> Flush()
|
||||
|
@ -122,6 +201,12 @@ namespace SaveState
|
|||
|
||||
void Process(u64 userdata, int cyclesLate)
|
||||
{
|
||||
if (!__KernelIsRunning())
|
||||
{
|
||||
ERROR_LOG(COMMON, "Savestate failure: Unable to load without kernel, this should never happen.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Operation> operations = Flush();
|
||||
SaveStart state;
|
||||
|
||||
|
@ -158,12 +243,21 @@ namespace SaveState
|
|||
}
|
||||
|
||||
if (op.callback != NULL)
|
||||
op.callback(result);
|
||||
op.callback(result, op.cbUserData);
|
||||
}
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
timer = CoreTiming::RegisterEvent("SaveState", Process);
|
||||
// Make sure there's a directory for save slots
|
||||
pspFileSystem.MkDir("ms0:/PSP/PPSSPP_STATE");
|
||||
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
if (needsProcess)
|
||||
{
|
||||
CoreTiming::ScheduleEvent(0, timer);
|
||||
needsProcess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,20 +20,28 @@
|
|||
|
||||
namespace SaveState
|
||||
{
|
||||
typedef void (*Callback)(bool status);
|
||||
typedef void (*Callback)(bool status, void *cbUserData);
|
||||
|
||||
// TODO: Better place for this?
|
||||
const int REVISION = 1;
|
||||
const int SAVESTATESLOTS = 4;
|
||||
|
||||
void Init();
|
||||
|
||||
void SaveSlot(int slot, Callback callback, void *cbUserData = 0);
|
||||
void LoadSlot(int slot, Callback callback, void *cbUserData = 0);
|
||||
void HasSaveInSlot(int slot);
|
||||
int GetNewestSlot();
|
||||
|
||||
// Load the specified file into the current state (async.)
|
||||
// Warning: callback will be called on a different thread.
|
||||
void Load(const std::string &filename, Callback callback = NULL);
|
||||
void Load(const std::string &filename, Callback callback = 0, void *cbUserData = 0);
|
||||
|
||||
// Save the current state to the specified file (async.)
|
||||
// Warning: callback will be called on a different thread.
|
||||
void Save(const std::string &filename, Callback callback = NULL);
|
||||
void Save(const std::string &filename, Callback callback = 0, void *cbUserData = 0);
|
||||
|
||||
// For testing / automated tests. Runs a save state verification pass (async.)
|
||||
// Warning: callback will be called on a different thread.
|
||||
void Verify(Callback callback = NULL);
|
||||
void Verify(Callback callback = 0, void *cbUserData = 0);
|
||||
};
|
||||
|
|
|
@ -37,10 +37,10 @@
|
|||
#include "CoreParameter.h"
|
||||
#include "FileSystems/MetaFileSystem.h"
|
||||
#include "Loaders.h"
|
||||
|
||||
#include "ELF/ParamSFO.h"
|
||||
|
||||
MetaFileSystem pspFileSystem;
|
||||
|
||||
ParamSFOData g_paramSFO;
|
||||
static CoreParameter coreParameter;
|
||||
|
||||
bool PSP_Init(const CoreParameter &coreParam, std::string *error_string)
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
#include "MemMap.h"
|
||||
#include "FileSystems/MetaFileSystem.h"
|
||||
#include "CoreParameter.h"
|
||||
#include "ELF/ParamSFO.h"
|
||||
|
||||
extern MetaFileSystem pspFileSystem;
|
||||
extern ParamSFOData g_paramSFO;
|
||||
|
||||
bool PSP_Init(const CoreParameter &coreParam, std::string *error_string);
|
||||
bool PSP_IsInited();
|
||||
|
|
|
@ -238,18 +238,20 @@ static void PPGeMeasureText(const char *text, float scale, float *w, float *h) {
|
|||
const AtlasFont &atlasfont = *ppge_atlas.fonts[0];
|
||||
unsigned char cval;
|
||||
float wacc = 0;
|
||||
float maxw = 0;
|
||||
int lines = 1;
|
||||
while ((cval = *text++) != '\0') {
|
||||
if (cval < 32) continue;
|
||||
if (cval > 127) continue;
|
||||
if (cval == '\n') {
|
||||
if (wacc > maxw) maxw = wacc;
|
||||
wacc = 0;
|
||||
lines++;
|
||||
}
|
||||
AtlasChar c = atlasfont.chars[cval - 32];
|
||||
wacc += c.wx * scale;
|
||||
}
|
||||
if (w) *w = wacc;
|
||||
if (w) *w = maxw;
|
||||
if (h) *h = atlasfont.height * scale * lines;
|
||||
}
|
||||
|
||||
|
@ -278,6 +280,7 @@ void PPGeDrawText(const char *text, float x, float y, int align, float scale, u3
|
|||
float sx = x;
|
||||
while ((cval = *text++) != '\0') {
|
||||
if (cval == '\n') {
|
||||
// This is not correct when centering or right-justifying, need to set x depending on line width (tricky)
|
||||
y += atlasfont.height * scale;
|
||||
x = sx;
|
||||
continue;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
set(SRCS
|
||||
GPUCommon.cpp
|
||||
GPUState.cpp
|
||||
Math3D.cpp
|
||||
GLES/DisplayListInterpreter.cpp
|
||||
|
|
|
@ -161,10 +161,8 @@ GLES_GPU::GLES_GPU(int renderWidth, int renderHeight)
|
|||
: interruptsEnabled_(true),
|
||||
displayFramebufPtr_(0),
|
||||
renderWidth_(renderWidth),
|
||||
renderHeight_(renderHeight),
|
||||
dlIdGenerator(1),
|
||||
dumpThisFrame_(false),
|
||||
dumpNextFrame_(false) {
|
||||
renderHeight_(renderHeight)
|
||||
{
|
||||
renderWidthFactor_ = (float)renderWidth / 480.0f;
|
||||
renderHeightFactor_ = (float)renderHeight / 272.0f;
|
||||
shaderManager_ = new ShaderManager();
|
||||
|
@ -177,10 +175,10 @@ GLES_GPU::GLES_GPU(int renderWidth, int renderHeight)
|
|||
|
||||
flushBeforeCommand_ = new u8[256];
|
||||
memset(flushBeforeCommand_, 0, 256 * sizeof(bool));
|
||||
for (int i = 0; i < ARRAY_SIZE(flushOnChangedBeforeCommandList); i++) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(flushOnChangedBeforeCommandList); i++) {
|
||||
flushBeforeCommand_[flushOnChangedBeforeCommandList[i]] = 2;
|
||||
}
|
||||
for (int i = 0; i < ARRAY_SIZE(flushBeforeCommandList); i++) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(flushBeforeCommandList); i++) {
|
||||
flushBeforeCommand_[flushBeforeCommandList[i]] = 1;
|
||||
}
|
||||
flushBeforeCommand_[1] = 0;
|
||||
|
@ -304,7 +302,16 @@ GLES_GPU::VirtualFramebuffer *GLES_GPU::GetDisplayFBO() {
|
|||
return *iter;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE, "Finding no FBO matching address %08x", displayFramebufPtr_);
|
||||
#ifdef _DEBUG
|
||||
std::string debug = "FBOs: ";
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
char temp[256];
|
||||
sprintf(temp, "%08x %i %i", (*iter)->fb_address, (*iter)->width, (*iter)->height);
|
||||
debug += std::string(temp);
|
||||
}
|
||||
ERROR_LOG(HLE, "FBOs: %s", debug.c_str());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -322,13 +329,19 @@ void GLES_GPU::SetRenderFrameBuffer() {
|
|||
int drawing_width = ((gstate.region2) & 0x3FF) + 1;
|
||||
int drawing_height = ((gstate.region2 >> 10) & 0x3FF) + 1;
|
||||
|
||||
// HACK for first frame where some games don't init things right
|
||||
if (drawing_width == 1 && drawing_height == 1) {
|
||||
drawing_width = 480;
|
||||
drawing_height = 272;
|
||||
}
|
||||
|
||||
int fmt = gstate.framebufpixformat & 3;
|
||||
|
||||
// Find a matching framebuffer
|
||||
VirtualFramebuffer *vfb = 0;
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
VirtualFramebuffer *v = *iter;
|
||||
if (v->fb_address == fb_address) {
|
||||
if (v->fb_address == fb_address && v->width == drawing_width && v->height == drawing_height) {
|
||||
// Let's not be so picky for now. Let's say this is the one.
|
||||
vfb = v;
|
||||
// Update fb stride in case it changed
|
||||
|
@ -355,7 +368,7 @@ void GLES_GPU::SetRenderFrameBuffer() {
|
|||
glViewport(0, 0, renderWidth_, renderHeight_);
|
||||
currentRenderVfb_ = vfb;
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
DEBUG_LOG(HLE, "Creating FBO for %08x", vfb->fb_address);
|
||||
INFO_LOG(HLE, "Creating FBO for %08x : %i x %i", vfb->fb_address, vfb->width, vfb->height);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -386,53 +399,8 @@ void GLES_GPU::EndDebugDraw() {
|
|||
|
||||
// Render queue
|
||||
|
||||
bool GLES_GPU::ProcessDLQueue() {
|
||||
std::vector<DisplayList>::iterator iter = dlQueue.begin();
|
||||
while (!(iter == dlQueue.end())) {
|
||||
DisplayList &l = *iter;
|
||||
dcontext.pc = l.listpc;
|
||||
dcontext.stallAddr = l.stall;
|
||||
// //DEBUG_LOG(G3D,"Okay, starting DL execution at %08 - stall = %08x", context.pc, stallAddr);
|
||||
if (!InterpretList()) {
|
||||
l.listpc = dcontext.pc;
|
||||
l.stall = dcontext.stallAddr;
|
||||
return false;
|
||||
} else {
|
||||
//At the end, we can remove it from the queue and continue
|
||||
dlQueue.erase(iter);
|
||||
//this invalidated the iterator, let's fix it
|
||||
iter = dlQueue.begin();
|
||||
}
|
||||
}
|
||||
return true; //no more lists!
|
||||
}
|
||||
|
||||
u32 GLES_GPU::EnqueueList(u32 listpc, u32 stall) {
|
||||
DisplayList dl;
|
||||
dl.id = dlIdGenerator++;
|
||||
dl.listpc = listpc & 0xFFFFFFF;
|
||||
dl.stall = stall & 0xFFFFFFF;
|
||||
dlQueue.push_back(dl);
|
||||
if (!ProcessDLQueue())
|
||||
return dl.id;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GLES_GPU::UpdateStall(int listid, u32 newstall) {
|
||||
// this needs improvement....
|
||||
for (std::vector<DisplayList>::iterator iter = dlQueue.begin(); iter != dlQueue.end(); iter++)
|
||||
{
|
||||
DisplayList &l = *iter;
|
||||
if (l.id == listid)
|
||||
{
|
||||
l.stall = newstall & 0xFFFFFFF;
|
||||
}
|
||||
}
|
||||
ProcessDLQueue();
|
||||
}
|
||||
|
||||
void GLES_GPU::DrawSync(int mode) {
|
||||
void GLES_GPU::DrawSync(int mode)
|
||||
{
|
||||
transformDraw_.Flush();
|
||||
}
|
||||
|
||||
|
@ -464,6 +432,13 @@ static void LeaveClearMode() {
|
|||
// dirtyshader?
|
||||
}
|
||||
|
||||
void GLES_GPU::PreExecuteOp(u32 op, u32 diff) {
|
||||
u32 cmd = op >> 24;
|
||||
|
||||
if (flushBeforeCommand_[cmd] == 1 || (diff && flushBeforeCommand_[cmd] == 2))
|
||||
transformDraw_.Flush();
|
||||
}
|
||||
|
||||
void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
||||
u32 cmd = op >> 24;
|
||||
u32 data = op & 0xFFFFFF;
|
||||
|
@ -509,7 +484,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
|||
}
|
||||
|
||||
int bytesRead;
|
||||
transformDraw_.SubmitPrim(verts, inds, type, count, gstate.vertType, 0, -1, &bytesRead);
|
||||
transformDraw_.SubmitPrim(verts, inds, type, count, gstate.vertType, -1, &bytesRead);
|
||||
// After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed).
|
||||
// Some games rely on this, they don't bother reloading VADDR and IADDR.
|
||||
// Q: Are these changed reflected in the real registers? Needs testing.
|
||||
|
@ -547,7 +522,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
|||
{
|
||||
u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF;
|
||||
if (Memory::IsValidAddress(target)) {
|
||||
dcontext.pc = target - 4; // pc will be increased after we return, counteract that
|
||||
currentList->pc = target - 4; // pc will be increased after we return, counteract that
|
||||
} else {
|
||||
ERROR_LOG(G3D, "JUMP to illegal address %08x - ignoring??", target);
|
||||
}
|
||||
|
@ -556,21 +531,21 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
|||
|
||||
case GE_CMD_CALL:
|
||||
{
|
||||
u32 retval = dcontext.pc + 4;
|
||||
u32 retval = currentList->pc + 4;
|
||||
if (stackptr == ARRAY_SIZE(stack)) {
|
||||
ERROR_LOG(G3D, "CALL: Stack full!");
|
||||
} else {
|
||||
stack[stackptr++] = retval;
|
||||
u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0xFFFFFFF;
|
||||
dcontext.pc = target - 4; // pc will be increased after we return, counteract that
|
||||
currentList->pc = target - 4; // pc will be increased after we return, counteract that
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GE_CMD_RET:
|
||||
{
|
||||
u32 target = (dcontext.pc & 0xF0000000) | (stack[--stackptr] & 0x0FFFFFFF);
|
||||
dcontext.pc = target - 4;
|
||||
u32 target = (currentList->pc & 0xF0000000) | (stack[--stackptr] & 0x0FFFFFFF);
|
||||
currentList->pc = target - 4;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -583,13 +558,14 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
|||
case GE_CMD_FINISH:
|
||||
// TODO: Should this run while interrupts are suspended?
|
||||
if (interruptsEnabled_)
|
||||
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, 0);
|
||||
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_FINISH, 0);
|
||||
break;
|
||||
|
||||
case GE_CMD_END:
|
||||
switch (prev >> 24) {
|
||||
case GE_CMD_SIGNAL:
|
||||
{
|
||||
currentList->status = PSP_GE_LIST_END_REACHED;
|
||||
// TODO: see http://code.google.com/p/jpcsp/source/detail?r=2935#
|
||||
int behaviour = (prev >> 16) & 0xFF;
|
||||
int signal = prev & 0xFFFF;
|
||||
|
@ -620,10 +596,11 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
|||
}
|
||||
// TODO: Should this run while interrupts are suspended?
|
||||
if (interruptsEnabled_)
|
||||
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, signal);
|
||||
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_SIGNAL, signal);
|
||||
}
|
||||
break;
|
||||
case GE_CMD_FINISH:
|
||||
currentList->status = PSP_GE_LIST_DONE;
|
||||
finished = true;
|
||||
break;
|
||||
default:
|
||||
|
@ -641,7 +618,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
|||
break;
|
||||
|
||||
case GE_CMD_ORIGIN:
|
||||
gstate.offsetAddr = dcontext.pc & 0xFFFFFF;
|
||||
gstate.offsetAddr = currentList->pc & 0xFFFFFF;
|
||||
break;
|
||||
|
||||
case GE_CMD_VERTEXTYPE:
|
||||
|
@ -1095,49 +1072,11 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
|||
break;
|
||||
|
||||
default:
|
||||
DEBUG_LOG(G3D,"DL Unknown: %08x @ %08x", op, dcontext.pc);
|
||||
DEBUG_LOG(G3D,"DL Unknown: %08x @ %08x", op, currentList == NULL ? 0 : currentList->pc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool GLES_GPU::InterpretList()
|
||||
{
|
||||
// Reset stackptr for safety
|
||||
stackptr = 0;
|
||||
u32 op = 0;
|
||||
prev = 0;
|
||||
finished = false;
|
||||
while (!finished)
|
||||
{
|
||||
if (!Memory::IsValidAddress(dcontext.pc)) {
|
||||
ERROR_LOG(G3D, "DL PC = %08x WTF!!!!", dcontext.pc);
|
||||
return true;
|
||||
}
|
||||
if (dcontext.pc == dcontext.stallAddr)
|
||||
return false;
|
||||
|
||||
op = Memory::ReadUnchecked_U32(dcontext.pc); //read from memory
|
||||
u32 cmd = op >> 24;
|
||||
u32 diff = op ^ gstate.cmdmem[cmd];
|
||||
if (flushBeforeCommand_[cmd] == 1 || (diff && flushBeforeCommand_[cmd] == 2))
|
||||
transformDraw_.Flush();
|
||||
// TODO: Add a compiler flag to remove stuff like this at very-final build time.
|
||||
if (dumpThisFrame_) {
|
||||
char temp[256];
|
||||
GeDisassembleOp(dcontext.pc, op, prev, temp);
|
||||
NOTICE_LOG(G3D, "%08x: %s", dcontext.pc, temp);
|
||||
}
|
||||
|
||||
gstate.cmdmem[cmd] = op;
|
||||
|
||||
ExecuteOp(op, diff);
|
||||
|
||||
dcontext.pc += 4;
|
||||
prev = op;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLES_GPU::UpdateStats() {
|
||||
gpuStats.numVertexShaders = shaderManager_->NumVertexShaders();
|
||||
gpuStats.numFragmentShaders = shaderManager_->NumFragmentShaders();
|
||||
|
@ -1196,3 +1135,16 @@ void GLES_GPU::InvalidateCache(u32 addr, int size) {
|
|||
void GLES_GPU::Flush() {
|
||||
transformDraw_.Flush();
|
||||
}
|
||||
|
||||
void GLES_GPU::DoState(PointerWrap &p) {
|
||||
GPUCommon::DoState(p);
|
||||
|
||||
TextureCache_Clear(true);
|
||||
gstate_c.textureChanged = true;
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
fbo_destroy((*iter)->fbo);
|
||||
delete (*iter);
|
||||
}
|
||||
vfbs_.clear();
|
||||
shaderManager_->ClearCache(true);
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
#include "../GPUInterface.h"
|
||||
#include "../GPUCommon.h"
|
||||
#include "Framebuffer.h"
|
||||
#include "VertexDecoder.h"
|
||||
#include "TransformPipeline.h"
|
||||
|
@ -29,16 +29,14 @@
|
|||
class ShaderManager;
|
||||
class LinkedShader;
|
||||
|
||||
class GLES_GPU : public GPUInterface
|
||||
class GLES_GPU : public GPUCommon
|
||||
{
|
||||
public:
|
||||
GLES_GPU(int renderWidth, int renderHeight);
|
||||
~GLES_GPU();
|
||||
virtual void InitClear();
|
||||
virtual u32 EnqueueList(u32 listpc, u32 stall);
|
||||
virtual void UpdateStall(int listid, u32 newstall);
|
||||
virtual void PreExecuteOp(u32 op, u32 diff);
|
||||
virtual void ExecuteOp(u32 op, u32 diff);
|
||||
virtual bool InterpretList();
|
||||
virtual void DrawSync(int mode);
|
||||
virtual void Continue();
|
||||
virtual void Break();
|
||||
|
@ -55,10 +53,10 @@ public:
|
|||
|
||||
virtual void DumpNextFrame();
|
||||
virtual void Flush();
|
||||
virtual void DoState(PointerWrap &p);
|
||||
|
||||
private:
|
||||
void DoBlockTransfer();
|
||||
bool ProcessDLQueue();
|
||||
|
||||
// Applies states for debugging if enabled.
|
||||
void BeginDebugDraw();
|
||||
|
@ -80,31 +78,12 @@ private:
|
|||
float renderWidthFactor_;
|
||||
float renderHeightFactor_;
|
||||
|
||||
bool dumpNextFrame_;
|
||||
bool dumpThisFrame_;
|
||||
|
||||
struct CmdProcessorState {
|
||||
u32 pc;
|
||||
u32 stallAddr;
|
||||
int subIntrBase;
|
||||
};
|
||||
|
||||
CmdProcessorState dcontext;
|
||||
|
||||
int dlIdGenerator;
|
||||
|
||||
struct DisplayList {
|
||||
int id;
|
||||
u32 listpc;
|
||||
u32 stall;
|
||||
};
|
||||
|
||||
std::vector<DisplayList> dlQueue;
|
||||
|
||||
u32 prev;
|
||||
u32 stack[2];
|
||||
u32 stackptr;
|
||||
bool finished;
|
||||
|
||||
struct VirtualFramebuffer {
|
||||
u32 fb_address;
|
||||
u32 z_address;
|
||||
|
|
|
@ -156,7 +156,7 @@ char *GenerateFragmentShader()
|
|||
}
|
||||
// Color doubling
|
||||
if (gstate.texfunc & 0x10000) {
|
||||
WRITE(p, " v = v * vec4(2.0, 2.0, 2.0, 1.0);");
|
||||
WRITE(p, " v = v * vec4(2.0, 2.0, 2.0, 2.0);");
|
||||
}
|
||||
|
||||
if (gstate.alphaTestEnable & 1) {
|
||||
|
|
|
@ -181,7 +181,6 @@ void UpdateViewportAndProjection() {
|
|||
|
||||
if (throughmode) {
|
||||
// No viewport transform here. Let's experiment with using region.
|
||||
return;
|
||||
glViewport((0 + regionX1) * renderWidthFactor, (0 - regionY1) * renderHeightFactor, (regionX2 - regionX1) * renderWidthFactor, (regionY2 - regionY1) * renderHeightFactor);
|
||||
} else {
|
||||
// These we can turn into a glViewport call, offset by offsetX and offsetY. Math after.
|
||||
|
@ -203,8 +202,6 @@ void UpdateViewportAndProjection() {
|
|||
gstate_c.vpWidth = vpXa * 2;
|
||||
gstate_c.vpHeight = -vpYa * 2;
|
||||
|
||||
return;
|
||||
|
||||
float vpWidth = fabsf(gstate_c.vpWidth);
|
||||
float vpHeight = fabsf(gstate_c.vpHeight);
|
||||
|
||||
|
|
|
@ -428,16 +428,12 @@ void UpdateSamplingParams()
|
|||
int tClamp = (gstate.texwrap>>8) & 1;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
// Tested mag/minFilt only work in either one case that can allow GL_LINEAR to be enable
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilt ? GL_LINEAR : GL_NEAREST);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilt ? GL_LINEAR : GL_NEAREST);
|
||||
// User define linear filtering
|
||||
if ( g_Config.bLinearFiltering ) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilt ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilt ? GL_LINEAR : GL_NEAREST);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,8 +64,7 @@ TransformDrawEngine::~TransformDrawEngine() {
|
|||
void TransformDrawEngine::DrawBezier(int ucount, int vcount) {
|
||||
u16 indices[3 * 3 * 6];
|
||||
|
||||
u32 customVertType = gstate.vertType; //(gstate.vertType & ~GE_VTYPE_TC_MASK) | GE_VTYPE_TC_FLOAT;
|
||||
float customUV[32];
|
||||
// Generate indices for a rectangular mesh.
|
||||
int c = 0;
|
||||
for (int y = 0; y < 3; y++) {
|
||||
for (int x = 0; x < 3; x++) {
|
||||
|
@ -78,6 +77,14 @@ void TransformDrawEngine::DrawBezier(int ucount, int vcount) {
|
|||
}
|
||||
}
|
||||
|
||||
// We are free to use the "decoded" buffer here.
|
||||
// Let's split it into two to get a second buffer, there's enough space.
|
||||
u8 *decoded2 = decoded + 65536 * 24;
|
||||
|
||||
// Alright, now for the vertex data.
|
||||
// For now, we will simply inject UVs.
|
||||
|
||||
float customUV[4 * 4 * 2];
|
||||
for (int y = 0; y < 4; y++) {
|
||||
for (int x = 0; x < 4; x++) {
|
||||
customUV[(y * 4 + x) * 2 + 0] = (float)x/3.0f;
|
||||
|
@ -85,8 +92,13 @@ void TransformDrawEngine::DrawBezier(int ucount, int vcount) {
|
|||
}
|
||||
}
|
||||
|
||||
int vertexCount = 3 * 3 * 6;
|
||||
SubmitPrim(Memory::GetPointer(gstate_c.vertexAddr), &indices[0], GE_PRIM_TRIANGLES, vertexCount, customVertType, customUV, GE_VTYPE_IDX_16BIT, 0);
|
||||
if (!(gstate.vertType & GE_VTYPE_TC_MASK)) {
|
||||
dec.SetVertexType(gstate.vertType);
|
||||
u32 newVertType = dec.InjectUVs(decoded2, Memory::GetPointer(gstate_c.vertexAddr), customUV, 16);
|
||||
SubmitPrim(decoded2, &indices[0], GE_PRIM_TRIANGLES, c, newVertType, GE_VTYPE_IDX_16BIT, 0);
|
||||
} else {
|
||||
SubmitPrim(Memory::GetPointer(gstate_c.vertexAddr), &indices[0], GE_PRIM_TRIANGLES, c, gstate.vertType, GE_VTYPE_IDX_16BIT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformDrawEngine::DrawSpline(int ucount, int vcount, int utype, int vtype) {
|
||||
|
@ -227,7 +239,7 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[
|
|||
dots[l] = dot;
|
||||
if (gstate.lightEnable[l] & 1)
|
||||
{
|
||||
Color4 lightAmbient(gstate_c.lightColor[2][l], 1.0f);
|
||||
Color4 lightAmbient(gstate_c.lightColor[0][l], 1.0f);
|
||||
lightSum0 += lightAmbient * *ambient + diff;
|
||||
}
|
||||
}
|
||||
|
@ -330,18 +342,6 @@ static void RotateUVs(TransformedVertex v[4]) {
|
|||
// GL_TRIANGLES. Still need to sw transform to compute the extra two corners though.
|
||||
void TransformDrawEngine::SoftwareTransformAndDraw(
|
||||
int prim, u8 *decoded, LinkedShader *program, int vertexCount, u32 vertType, void *inds, int indexType, const DecVtxFormat &decVtxFormat, int maxIndex) {
|
||||
/*
|
||||
DEBUG_LOG(G3D, "View matrix:");
|
||||
const float *m = &gstate.viewMatrix[0];
|
||||
DEBUG_LOG(G3D, "%f %f %f", m[0], m[1], m[2]);
|
||||
DEBUG_LOG(G3D, "%f %f %f", m[3], m[4], m[5]);
|
||||
DEBUG_LOG(G3D, "%f %f %f", m[6], m[7], m[8]);
|
||||
DEBUG_LOG(G3D, "%f %f %f", m[9], m[10], m[11]);
|
||||
*/
|
||||
|
||||
// Temporary storage for RECTANGLES emulation
|
||||
float v2[3] = {0};
|
||||
float uv2[2] = {0};
|
||||
|
||||
bool throughmode = (vertType & GE_VTYPE_THROUGH_MASK) != 0;
|
||||
|
||||
|
@ -372,9 +372,9 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
|
|||
c1[j] = 0.0f;
|
||||
}
|
||||
} else {
|
||||
c0[0] = (gstate.materialambient & 0xFF) / 255.f;
|
||||
c0[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f;
|
||||
c0[2] = ((gstate.materialambient >> 16) & 0xFF) / 255.f;
|
||||
c0[0] = ((gstate.materialambient >> 16) & 0xFF) / 255.f;
|
||||
c0[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f;
|
||||
c0[2] = (gstate.materialambient & 0xFF) / 255.f;
|
||||
c0[3] = (gstate.materialalpha & 0xFF) / 255.f;
|
||||
}
|
||||
|
||||
|
@ -431,9 +431,9 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
|
|||
if (reader.hasColor0()) {
|
||||
reader.ReadColor0(unlitColor);
|
||||
} else {
|
||||
unlitColor[0] = (gstate.materialambient & 0xFF) / 255.f;
|
||||
unlitColor[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f;
|
||||
unlitColor[2] = ((gstate.materialambient >> 16) & 0xFF) / 255.f;
|
||||
unlitColor[0] = ((gstate.materialambient >> 16) & 0xFF) / 255.f;
|
||||
unlitColor[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f;
|
||||
unlitColor[2] = (gstate.materialambient & 0xFF) / 255.f;
|
||||
unlitColor[3] = (gstate.materialalpha & 0xFF) / 255.f;
|
||||
}
|
||||
float litColor0[4];
|
||||
|
@ -462,9 +462,9 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
|
|||
c1[j] = 0.0f;
|
||||
}
|
||||
} else {
|
||||
c0[0] = (gstate.materialambient & 0xFF) / 255.f;
|
||||
c0[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f;
|
||||
c0[2] = ((gstate.materialambient >> 16) & 0xFF) / 255.f;
|
||||
c0[0] = ((gstate.materialambient >> 16) & 0xFF) / 255.f;
|
||||
c0[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f;
|
||||
c0[2] = (gstate.materialambient & 0xFF) / 255.f;
|
||||
c0[3] = (gstate.materialalpha & 0xFF) / 255.f;
|
||||
}
|
||||
}
|
||||
|
@ -541,6 +541,10 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
|
|||
numTrans = vertexCount;
|
||||
drawIndexed = true;
|
||||
} else {
|
||||
// Temporary storage for RECTANGLES emulation
|
||||
float v2[3] = {0};
|
||||
float uv2[2] = {0};
|
||||
|
||||
numTrans = 0;
|
||||
drawBuffer = transformedExpanded;
|
||||
TransformedVertex *trans = &transformedExpanded[0];
|
||||
|
@ -615,7 +619,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
|
|||
if (program->a_color1 != -1) glDisableVertexAttribArray(program->a_color1);
|
||||
}
|
||||
|
||||
void TransformDrawEngine::SubmitPrim(void *verts, void *inds, int prim, int vertexCount, u32 vertType, float *customUV, int forceIndexType, int *bytesRead) {
|
||||
void TransformDrawEngine::SubmitPrim(void *verts, void *inds, int prim, int vertexCount, u32 vertType, int forceIndexType, int *bytesRead) {
|
||||
// For the future
|
||||
if (!indexGen.PrimCompatible(prim))
|
||||
Flush();
|
||||
|
|
|
@ -29,7 +29,7 @@ class TransformDrawEngine {
|
|||
public:
|
||||
TransformDrawEngine();
|
||||
~TransformDrawEngine();
|
||||
void SubmitPrim(void *verts, void *inds, int prim, int vertexCount, u32 vertexType, float *customUV, int forceIndexType, int *bytesRead);
|
||||
void SubmitPrim(void *verts, void *inds, int prim, int vertexCount, u32 vertexType, int forceIndexType, int *bytesRead);
|
||||
void DrawBezier(int ucount, int vcount);
|
||||
void DrawSpline(int ucount, int vcount, int utype, int vtype);
|
||||
void Flush();
|
||||
|
|
|
@ -645,8 +645,7 @@ void VertexDecoder::SetVertexType(u32 fmt) {
|
|||
DEBUG_LOG(G3D,"SVT : size = %i, aligned to biggest %i", size, biggest);
|
||||
}
|
||||
|
||||
void VertexDecoder::DecodeVerts(u8 *decodedptr, const void *verts, const void *inds, int prim, int count, int *indexLowerBound, int *indexUpperBound) const
|
||||
{
|
||||
void VertexDecoder::DecodeVerts(u8 *decodedptr, const void *verts, const void *inds, int prim, int count, int *indexLowerBound, int *indexUpperBound) const {
|
||||
// Find index bounds. Could cache this in display lists.
|
||||
// Also, this could be greatly sped up with SSE2, although rarely a bottleneck.
|
||||
int lowerBound = 0x7FFFFFFF;
|
||||
|
@ -677,8 +676,7 @@ void VertexDecoder::DecodeVerts(u8 *decodedptr, const void *verts, const void *i
|
|||
// Decode the vertices within the found bounds, once each
|
||||
decoded_ = decodedptr; // + lowerBound * decFmt.stride;
|
||||
ptr_ = (const u8*)verts + lowerBound * size;
|
||||
for (int index = lowerBound; index <= upperBound; index++)
|
||||
{
|
||||
for (int index = lowerBound; index <= upperBound; index++) {
|
||||
for (int i = 0; i < numSteps_; i++) {
|
||||
((*this).*steps_[i])();
|
||||
}
|
||||
|
@ -686,3 +684,24 @@ void VertexDecoder::DecodeVerts(u8 *decodedptr, const void *verts, const void *i
|
|||
decoded_ += decFmt.stride;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Does not support morphs, skinning etc.
|
||||
u32 VertexDecoder::InjectUVs(u8 *decoded, const void *verts, float *customuv, int count) const {
|
||||
u32 customVertType = (gstate.vertType & ~GE_VTYPE_TC_MASK) | GE_VTYPE_TC_FLOAT;
|
||||
VertexDecoder decOut;
|
||||
decOut.SetVertexType(customVertType);
|
||||
|
||||
const u8 *inp = (const u8 *)verts;
|
||||
u8 *out = decoded;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (pos) memcpy(out + decOut.posoff, inp + posoff, possize[pos]);
|
||||
if (nrm) memcpy(out + decOut.nrmoff, inp + nrmoff, nrmsize[pos]);
|
||||
if (col) memcpy(out + decOut.coloff, inp + coloff, colsize[pos]);
|
||||
// Ignore others for now, this is all we need for puzbob.
|
||||
// Inject!
|
||||
memcpy(out + decOut.tcoff, &customuv[i * 2], tcsize[decOut.tc]);
|
||||
inp += this->onesize_;
|
||||
out += decOut.onesize_;
|
||||
}
|
||||
return customVertType;
|
||||
}
|
||||
|
|
|
@ -88,6 +88,10 @@ public:
|
|||
const DecVtxFormat &GetDecVtxFmt() { return decFmt; }
|
||||
|
||||
void DecodeVerts(u8 *decoded, const void *verts, const void *inds, int prim, int count, int *indexLowerBound, int *indexUpperBound) const;
|
||||
|
||||
// This could be easily generalized to inject any one component. Don't know another use for it though.
|
||||
u32 InjectUVs(u8 *decoded, const void *verts, float *customuv, int count) const;
|
||||
|
||||
bool hasColor() const { return col != 0; }
|
||||
int VertexSize() const { return size; }
|
||||
|
||||
|
|
|
@ -128,6 +128,7 @@
|
|||
<ClInclude Include="GLES\VertexDecoder.h" />
|
||||
<ClInclude Include="GLES\VertexShaderGenerator.h" />
|
||||
<ClInclude Include="GeDisasm.h" />
|
||||
<ClInclude Include="GPUCommon.h" />
|
||||
<ClInclude Include="GPUInterface.h" />
|
||||
<ClInclude Include="GPUState.h" />
|
||||
<ClInclude Include="Math3D.h" />
|
||||
|
@ -147,6 +148,7 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="GLES\VertexShaderGenerator.cpp" />
|
||||
<ClCompile Include="GeDisasm.cpp" />
|
||||
<ClCompile Include="GPUCommon.cpp" />
|
||||
<ClCompile Include="GPUState.cpp" />
|
||||
<ClCompile Include="Math3D.cpp" />
|
||||
<ClCompile Include="Null\NullGpu.cpp" />
|
||||
|
@ -162,4 +164,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
|
@ -60,6 +60,10 @@
|
|||
<ClInclude Include="GLES\IndexGenerator.h">
|
||||
<Filter>GLES</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GeDisasm.h" />
|
||||
<ClInclude Include="GPUCommon.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Math3D.cpp">
|
||||
|
@ -101,6 +105,10 @@
|
|||
<ClCompile Include="GLES\IndexGenerator.cpp">
|
||||
<Filter>GLES</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeDisasm.cpp" />
|
||||
<ClCompile Include="GPUCommon.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
|
|
127
GPU/GPUCommon.cpp
Normal file
127
GPU/GPUCommon.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
#include "../Core/MemMap.h"
|
||||
#include "GeDisasm.h"
|
||||
#include "GPUCommon.h"
|
||||
#include "GPUState.h"
|
||||
|
||||
|
||||
|
||||
static int dlIdGenerator = 1;
|
||||
|
||||
void init() {
|
||||
dlIdGenerator = 1;
|
||||
}
|
||||
|
||||
int GPUCommon::listStatus(int listid)
|
||||
{
|
||||
for(DisplayListQueue::iterator it(dlQueue.begin()); it != dlQueue.end(); ++it)
|
||||
{
|
||||
if(it->id == listid)
|
||||
{
|
||||
return it->status;
|
||||
}
|
||||
}
|
||||
return 0x80000100; // INVALID_ID
|
||||
}
|
||||
|
||||
u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head)
|
||||
{
|
||||
DisplayList dl;
|
||||
dl.id = dlIdGenerator++;
|
||||
dl.pc = listpc & 0xFFFFFFF;
|
||||
dl.stall = stall & 0xFFFFFFF;
|
||||
dl.status = PSP_GE_LIST_QUEUED;
|
||||
dl.subIntrBase = subIntrBase;
|
||||
if(head)
|
||||
dlQueue.push_front(dl);
|
||||
else
|
||||
dlQueue.push_back(dl);
|
||||
ProcessDLQueue();
|
||||
return dl.id;
|
||||
}
|
||||
|
||||
void GPUCommon::UpdateStall(int listid, u32 newstall)
|
||||
{
|
||||
// this needs improvement....
|
||||
for (DisplayListQueue::iterator iter = dlQueue.begin(); iter != dlQueue.end(); iter++)
|
||||
{
|
||||
DisplayList &l = *iter;
|
||||
if (l.id == listid)
|
||||
{
|
||||
l.stall = newstall & 0xFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
ProcessDLQueue();
|
||||
}
|
||||
|
||||
bool GPUCommon::InterpretList(DisplayList &list)
|
||||
{
|
||||
currentList = &list;
|
||||
// Reset stackptr for safety
|
||||
stackptr = 0;
|
||||
u32 op = 0;
|
||||
prev = 0;
|
||||
finished = false;
|
||||
while (!finished)
|
||||
{
|
||||
list.status = PSP_GE_LIST_DRAWING;
|
||||
if (!Memory::IsValidAddress(list.pc)) {
|
||||
ERROR_LOG(G3D, "DL PC = %08x WTF!!!!", list.pc);
|
||||
return true;
|
||||
}
|
||||
if (list.pc == list.stall)
|
||||
{
|
||||
list.status = PSP_GE_LIST_STALL_REACHED;
|
||||
return false;
|
||||
}
|
||||
op = Memory::ReadUnchecked_U32(list.pc); //read from memory
|
||||
u32 cmd = op >> 24;
|
||||
u32 diff = op ^ gstate.cmdmem[cmd];
|
||||
PreExecuteOp(op, diff);
|
||||
// TODO: Add a compiler flag to remove stuff like this at very-final build time.
|
||||
if (dumpThisFrame_) {
|
||||
char temp[256];
|
||||
GeDisassembleOp(list.pc, op, prev, temp);
|
||||
NOTICE_LOG(G3D, "%s", temp);
|
||||
}
|
||||
gstate.cmdmem[cmd] = op; // crashes if I try to put the whole op there??
|
||||
|
||||
ExecuteOp(op, diff);
|
||||
|
||||
list.pc += 4;
|
||||
prev = op;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GPUCommon::ProcessDLQueue()
|
||||
{
|
||||
DisplayListQueue::iterator iter = dlQueue.begin();
|
||||
while (!(iter == dlQueue.end()))
|
||||
{
|
||||
DisplayList &l = *iter;
|
||||
DEBUG_LOG(G3D,"Okay, starting DL execution at %08x - stall = %08x", l.pc, l.stall);
|
||||
if (!InterpretList(l))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//At the end, we can remove it from the queue and continue
|
||||
dlQueue.erase(iter);
|
||||
//this invalidated the iterator, let's fix it
|
||||
iter = dlQueue.begin();
|
||||
}
|
||||
}
|
||||
return true; //no more lists!
|
||||
}
|
||||
|
||||
void GPUCommon::PreExecuteOp(u32 op, u32 diff) {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void GPUCommon::DoState(PointerWrap &p) {
|
||||
p.Do(dlIdGenerator);
|
||||
p.Do<DisplayList>(dlQueue);
|
||||
p.DoMarker("GPUCommon");
|
||||
}
|
38
GPU/GPUCommon.h
Normal file
38
GPU/GPUCommon.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include "GPUInterface.h"
|
||||
|
||||
class GPUCommon : public GPUInterface
|
||||
{
|
||||
public:
|
||||
GPUCommon() :
|
||||
dlIdGenerator(1),
|
||||
currentList(NULL),
|
||||
stackptr(0),
|
||||
dumpNextFrame_(false),
|
||||
dumpThisFrame_(false)
|
||||
{}
|
||||
|
||||
virtual void PreExecuteOp(u32 op, u32 diff);
|
||||
virtual bool InterpretList(DisplayList &list);
|
||||
virtual bool ProcessDLQueue();
|
||||
virtual void UpdateStall(int listid, u32 newstall);
|
||||
virtual u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head);
|
||||
virtual int listStatus(int listid);
|
||||
virtual void DoState(PointerWrap &p);
|
||||
|
||||
protected:
|
||||
typedef std::deque<DisplayList> DisplayListQueue;
|
||||
|
||||
int dlIdGenerator;
|
||||
DisplayList *currentList;
|
||||
DisplayListQueue dlQueue;
|
||||
|
||||
u32 prev;
|
||||
u32 stack[2];
|
||||
u32 stackptr;
|
||||
bool finished;
|
||||
|
||||
bool dumpNextFrame_;
|
||||
bool dumpThisFrame_;
|
||||
};
|
|
@ -18,6 +18,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "../Globals.h"
|
||||
#include "../Common/ChunkFile.h"
|
||||
#include <deque>
|
||||
|
||||
enum DisplayListStatus
|
||||
{
|
||||
PSP_GE_LIST_DONE = 0, // reached finish+end
|
||||
PSP_GE_LIST_QUEUED = 1, // in queue, not stalled
|
||||
PSP_GE_LIST_DRAWING = 2, // drawing
|
||||
PSP_GE_LIST_STALL_REACHED = 3, // stalled
|
||||
PSP_GE_LIST_END_REACHED = 4, // reached signal+end, in jpcsp but not in pspsdk?
|
||||
PSP_GE_LIST_CANCEL_DONE = 5, // canceled?
|
||||
};
|
||||
|
||||
struct DisplayList
|
||||
{
|
||||
int id;
|
||||
u32 pc;
|
||||
u32 stall;
|
||||
DisplayListStatus status;
|
||||
int subIntrBase;
|
||||
};
|
||||
|
||||
class GPUInterface
|
||||
{
|
||||
|
@ -29,13 +50,15 @@ public:
|
|||
|
||||
// Draw queue management
|
||||
// TODO: Much of this should probably be shared between the different GPU implementations.
|
||||
virtual u32 EnqueueList(u32 listpc, u32 stall) = 0;
|
||||
virtual u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head) = 0;
|
||||
virtual void UpdateStall(int listid, u32 newstall) = 0;
|
||||
virtual void DrawSync(int mode) = 0;
|
||||
virtual void Continue() = 0;
|
||||
|
||||
virtual void PreExecuteOp(u32 op, u32 diff) = 0;
|
||||
virtual void ExecuteOp(u32 op, u32 diff) = 0;
|
||||
virtual bool InterpretList() = 0;
|
||||
virtual bool InterpretList(DisplayList& list) = 0;
|
||||
virtual int listStatus(int listid) = 0;
|
||||
|
||||
// Framebuffer management
|
||||
virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, int format) = 0;
|
||||
|
@ -54,6 +77,7 @@ public:
|
|||
|
||||
virtual void DeviceLost() = 0;
|
||||
virtual void Flush() = 0;
|
||||
virtual void DoState(PointerWrap &p) = 0;
|
||||
|
||||
// Debugging
|
||||
virtual void DumpNextFrame() = 0;
|
||||
|
|
|
@ -95,7 +95,8 @@ void ReapplyGfxState()
|
|||
|
||||
for (int i = GE_CMD_VERTEXTYPE; i < GE_CMD_BONEMATRIXNUMBER; i++)
|
||||
{
|
||||
gpu->ExecuteOp(gstate.cmdmem[i], 0xFFFFFFFF);
|
||||
if(i != GE_CMD_ORIGIN)
|
||||
gpu->ExecuteOp(gstate.cmdmem[i], 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
// Can't write to bonematrixnumber here
|
||||
|
|
|
@ -22,93 +22,13 @@
|
|||
#include "../../Core/MemMap.h"
|
||||
#include "../../Core/HLE/sceKernelInterrupt.h"
|
||||
|
||||
struct DisplayState
|
||||
{
|
||||
u32 pc;
|
||||
u32 stallAddr;
|
||||
};
|
||||
|
||||
static DisplayState dcontext;
|
||||
|
||||
struct DisplayList
|
||||
{
|
||||
int id;
|
||||
u32 listpc;
|
||||
u32 stall;
|
||||
};
|
||||
|
||||
static std::vector<DisplayList> dlQueue;
|
||||
|
||||
static u32 prev;
|
||||
static u32 stack[2];
|
||||
static u32 stackptr = 0;
|
||||
static bool finished;
|
||||
|
||||
static int dlIdGenerator = 1;
|
||||
|
||||
NullGPU::NullGPU()
|
||||
{
|
||||
interruptsEnabled_ = true;
|
||||
dlIdGenerator = 1;
|
||||
}
|
||||
|
||||
NullGPU::~NullGPU()
|
||||
{
|
||||
dlQueue.clear();
|
||||
}
|
||||
|
||||
bool NullGPU::ProcessDLQueue()
|
||||
{
|
||||
std::vector<DisplayList>::iterator iter = dlQueue.begin();
|
||||
while (!(iter == dlQueue.end()))
|
||||
{
|
||||
DisplayList &l = *iter;
|
||||
dcontext.pc = l.listpc;
|
||||
dcontext.stallAddr = l.stall;
|
||||
// DEBUG_LOG(G3D,"Okay, starting DL execution at %08 - stall = %08x", context.pc, stallAddr);
|
||||
if (!InterpretList())
|
||||
{
|
||||
l.listpc = dcontext.pc;
|
||||
l.stall = dcontext.stallAddr;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//At the end, we can remove it from the queue and continue
|
||||
dlQueue.erase(iter);
|
||||
//this invalidated the iterator, let's fix it
|
||||
iter = dlQueue.begin();
|
||||
}
|
||||
}
|
||||
return true; //no more lists!
|
||||
}
|
||||
|
||||
u32 NullGPU::EnqueueList(u32 listpc, u32 stall)
|
||||
{
|
||||
DisplayList dl;
|
||||
dl.id = dlIdGenerator++;
|
||||
dl.listpc = listpc&0xFFFFFFF;
|
||||
dl.stall = stall&0xFFFFFFF;
|
||||
dlQueue.push_back(dl);
|
||||
if (!ProcessDLQueue())
|
||||
return dl.id;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NullGPU::UpdateStall(int listid, u32 newstall)
|
||||
{
|
||||
// this needs improvement....
|
||||
for (std::vector<DisplayList>::iterator iter = dlQueue.begin(); iter != dlQueue.end(); iter++)
|
||||
{
|
||||
DisplayList &l = *iter;
|
||||
if (l.id == listid)
|
||||
{
|
||||
l.stall = newstall & 0xFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
ProcessDLQueue();
|
||||
}
|
||||
|
||||
void NullGPU::DrawSync(int mode)
|
||||
|
@ -124,7 +44,6 @@ void NullGPU::Continue()
|
|||
|
||||
}
|
||||
|
||||
|
||||
void NullGPU::ExecuteOp(u32 op, u32 diff)
|
||||
{
|
||||
u32 cmd = op >> 24;
|
||||
|
@ -187,18 +106,18 @@ void NullGPU::ExecuteOp(u32 op, u32 diff)
|
|||
case GE_CMD_JUMP:
|
||||
{
|
||||
u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF;
|
||||
DEBUG_LOG(G3D,"DL CMD JUMP - %08x to %08x", dcontext.pc, target);
|
||||
dcontext.pc = target - 4; // pc will be increased after we return, counteract that
|
||||
DEBUG_LOG(G3D,"DL CMD JUMP - %08x to %08x", currentList->pc, target);
|
||||
currentList->pc = target - 4; // pc will be increased after we return, counteract that
|
||||
}
|
||||
break;
|
||||
|
||||
case GE_CMD_CALL:
|
||||
{
|
||||
u32 retval = dcontext.pc + 4;
|
||||
u32 retval = currentList->pc + 4;
|
||||
stack[stackptr++] = retval;
|
||||
u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0xFFFFFFF;
|
||||
DEBUG_LOG(G3D,"DL CMD CALL - %08x to %08x, ret=%08x", dcontext.pc, target, retval);
|
||||
dcontext.pc = target - 4; // pc will be increased after we return, counteract that
|
||||
DEBUG_LOG(G3D,"DL CMD CALL - %08x to %08x, ret=%08x", currentList->pc, target, retval);
|
||||
currentList->pc = target - 4; // pc will be increased after we return, counteract that
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -206,8 +125,8 @@ void NullGPU::ExecuteOp(u32 op, u32 diff)
|
|||
//TODO : debug!
|
||||
{
|
||||
u32 target = stack[--stackptr] & 0xFFFFFFF;
|
||||
DEBUG_LOG(G3D,"DL CMD RET - from %08x to %08x", dcontext.pc, target);
|
||||
dcontext.pc = target - 4;
|
||||
DEBUG_LOG(G3D,"DL CMD RET - from %08x to %08x", currentList->pc, target);
|
||||
currentList->pc = target - 4;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -219,7 +138,7 @@ void NullGPU::ExecuteOp(u32 op, u32 diff)
|
|||
|
||||
// TODO: Should this run while interrupts are suspended?
|
||||
if (interruptsEnabled_)
|
||||
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, signal);
|
||||
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_SIGNAL, signal);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -234,7 +153,7 @@ void NullGPU::ExecuteOp(u32 op, u32 diff)
|
|||
break;
|
||||
|
||||
case GE_CMD_ORIGIN:
|
||||
gstate.offsetAddr = dcontext.pc & 0xFFFFFF;
|
||||
gstate.offsetAddr = currentList->pc & 0xFFFFFF;
|
||||
break;
|
||||
|
||||
case GE_CMD_VERTEXTYPE:
|
||||
|
@ -251,7 +170,7 @@ void NullGPU::ExecuteOp(u32 op, u32 diff)
|
|||
DEBUG_LOG(G3D,"DL CMD FINISH");
|
||||
// TODO: Should this run while interrupts are suspended?
|
||||
if (interruptsEnabled_)
|
||||
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, 0);
|
||||
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_FINISH, 0);
|
||||
break;
|
||||
|
||||
case GE_CMD_END:
|
||||
|
@ -807,38 +726,13 @@ void NullGPU::ExecuteOp(u32 op, u32 diff)
|
|||
break;
|
||||
|
||||
default:
|
||||
DEBUG_LOG(G3D,"DL Unknown: %08x @ %08x", op, dcontext.pc);
|
||||
DEBUG_LOG(G3D,"DL Unknown: %08x @ %08x", op, currentList->pc);
|
||||
break;
|
||||
|
||||
//ETC...
|
||||
}
|
||||
}
|
||||
|
||||
bool NullGPU::InterpretList()
|
||||
{
|
||||
// Reset stackptr for safety
|
||||
stackptr = 0;
|
||||
u32 op = 0;
|
||||
prev = 0;
|
||||
finished = false;
|
||||
while (!finished)
|
||||
{
|
||||
if (dcontext.pc == dcontext.stallAddr)
|
||||
return false;
|
||||
|
||||
op = Memory::ReadUnchecked_U32(dcontext.pc); //read from memory
|
||||
u32 cmd = op >> 24;
|
||||
u32 diff = op ^ gstate.cmdmem[cmd];
|
||||
gstate.cmdmem[cmd] = op; // crashes if I try to put the whole op there??
|
||||
|
||||
ExecuteOp(op, diff);
|
||||
|
||||
dcontext.pc += 4;
|
||||
prev = op;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NullGPU::UpdateStats()
|
||||
{
|
||||
gpuStats.numVertexShaders = 0;
|
||||
|
|
|
@ -17,20 +17,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../GPUInterface.h"
|
||||
#include "../GPUCommon.h"
|
||||
|
||||
class ShaderManager;
|
||||
|
||||
class NullGPU : public GPUInterface
|
||||
class NullGPU : public GPUCommon
|
||||
{
|
||||
public:
|
||||
NullGPU();
|
||||
~NullGPU();
|
||||
virtual void InitClear() {}
|
||||
virtual u32 EnqueueList(u32 listpc, u32 stall);
|
||||
virtual void UpdateStall(int listid, u32 newstall);
|
||||
virtual void ExecuteOp(u32 op, u32 diff);
|
||||
virtual bool InterpretList();
|
||||
virtual void Continue();
|
||||
virtual void DrawSync(int mode);
|
||||
virtual void EnableInterrupts(bool enable) {
|
||||
|
@ -48,6 +45,5 @@ public:
|
|||
virtual void DumpNextFrame() {}
|
||||
|
||||
private:
|
||||
bool ProcessDLQueue();
|
||||
bool interruptsEnabled_;
|
||||
};
|
||||
|
|
|
@ -136,6 +136,8 @@ SOURCES += ../Core/CPU.cpp \ # Core
|
|||
../GPU/GLES/TransformPipeline.cpp \
|
||||
../GPU/GLES/VertexDecoder.cpp \
|
||||
../GPU/GLES/VertexShaderGenerator.cpp \
|
||||
../GPU/GeDisasm.cpp \
|
||||
../GPU/GPUCommon.cpp \
|
||||
../GPU/GPUState.cpp \
|
||||
../GPU/Math3D.cpp \
|
||||
../GPU/Null/NullGpu.cpp \ # Kirk
|
||||
|
@ -245,6 +247,8 @@ HEADERS += ../Core/CPU.h \
|
|||
../GPU/GLES/VertexDecoder.h \
|
||||
../GPU/GLES/VertexShaderGenerator.h \
|
||||
../GPU/GPUInterface.h \
|
||||
../GPU/GeDisasm.h \
|
||||
../GPU/GPUCommon.h \
|
||||
../GPU/GPUState.h \
|
||||
../GPU/Math3D.h \
|
||||
../GPU/Null/NullGpu.h \
|
||||
|
|
|
@ -78,6 +78,7 @@ DWORD TheThread(LPVOID x)
|
|||
coreParameter.outputHeight = 272 * g_Config.iWindowZoom;
|
||||
coreParameter.pixelWidth = 480 * g_Config.iWindowZoom;
|
||||
coreParameter.pixelHeight = 272 * g_Config.iWindowZoom;
|
||||
coreParameter.startPaused = !g_Config.bAutoRun;
|
||||
|
||||
std::string error_string;
|
||||
if (!PSP_Init(coreParameter, &error_string))
|
||||
|
@ -89,20 +90,8 @@ DWORD TheThread(LPVOID x)
|
|||
INFO_LOG(BOOT, "Done.");
|
||||
_dbg_update_();
|
||||
|
||||
if (g_Config.bAutoRun)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
host->UpdateDisassembly();
|
||||
#endif
|
||||
Core_EnableStepping(FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
host->UpdateDisassembly();
|
||||
#endif
|
||||
Core_EnableStepping(TRUE);
|
||||
}
|
||||
host->UpdateDisassembly();
|
||||
Core_EnableStepping(coreParameter.startPaused ? TRUE : FALSE);
|
||||
|
||||
g_State.bBooted = true;
|
||||
#ifdef _DEBUG
|
||||
|
|
|
@ -43,10 +43,10 @@ int KeyboardDevice::UpdateState() {
|
|||
|
||||
switch (analog_ctrl_map[i + 1]) {
|
||||
case CTRL_UP:
|
||||
analogY -= .8f;
|
||||
analogY += .8f;
|
||||
break;
|
||||
case CTRL_DOWN:
|
||||
analogY += .8f;
|
||||
analogY -= .8f;
|
||||
break;
|
||||
case CTRL_LEFT:
|
||||
analogX -= .8f;
|
||||
|
|
|
@ -112,9 +112,10 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<RandomizedBaseAddress>true</RandomizedBaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<LargeAddressAware>true</LargeAddressAware>
|
||||
<BaseAddress>0x00400000</BaseAddress>
|
||||
<FixedBaseAddress>true</FixedBaseAddress>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
@ -139,7 +140,7 @@
|
|||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
<RandomizedBaseAddress>true</RandomizedBaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<LargeAddressAware>true</LargeAddressAware>
|
||||
<BaseAddress>0x00400000</BaseAddress>
|
||||
</Link>
|
||||
|
@ -175,6 +176,11 @@
|
|||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
<BaseAddress>0x00400000</BaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<FixedBaseAddress>true</FixedBaseAddress>
|
||||
<LargeAddressAware>true</LargeAddressAware>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
|
@ -38,7 +38,7 @@ void WindowsHost::ShutdownGL()
|
|||
void WindowsHost::SetWindowTitle(const char *message)
|
||||
{
|
||||
// Really need a better way to deal with versions.
|
||||
std::string title = "PPSSPP v0.4 - ";
|
||||
std::string title = "PPSSPP v0.5 - ";
|
||||
title += message;
|
||||
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, message, title.size(), NULL, 0);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003.
|
||||
|
||||
|
||||
#define programname "PPSSPP v0.4"
|
||||
#define programname "PPSSPP v0.5"
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
|
@ -61,6 +61,7 @@ namespace MainWindow
|
|||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
LRESULT CALLBACK DisplayProc(HWND, UINT, WPARAM, LPARAM);
|
||||
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
|
||||
LRESULT CALLBACK Controls(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
HWND GetHWND()
|
||||
{
|
||||
|
@ -312,7 +313,14 @@ namespace MainWindow
|
|||
UpdateMenus();
|
||||
break;
|
||||
|
||||
case ID_FILE_LOADSTATE:
|
||||
case ID_FILE_LOADSTATEFILE:
|
||||
if (g_State.bEmuThreadStarted)
|
||||
{
|
||||
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
|
||||
for (int i=0; i<numCPUs; i++)
|
||||
if (disasmWindow[i])
|
||||
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
|
||||
}
|
||||
if (W32Util::BrowseForFileName(true, hWnd, "Load state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn))
|
||||
{
|
||||
SetCursor(LoadCursor(0,IDC_WAIT));
|
||||
|
@ -320,7 +328,14 @@ namespace MainWindow
|
|||
}
|
||||
break;
|
||||
|
||||
case ID_FILE_SAVESTATE:
|
||||
case ID_FILE_SAVESTATEFILE:
|
||||
if (g_State.bEmuThreadStarted)
|
||||
{
|
||||
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
|
||||
for (int i=0; i<numCPUs; i++)
|
||||
if (disasmWindow[i])
|
||||
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
|
||||
}
|
||||
if (W32Util::BrowseForFileName(false, hWnd, "Save state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn))
|
||||
{
|
||||
SetCursor(LoadCursor(0,IDC_WAIT));
|
||||
|
@ -328,6 +343,32 @@ namespace MainWindow
|
|||
}
|
||||
break;
|
||||
|
||||
// TODO: Add UI for multiple slots
|
||||
|
||||
case ID_FILE_QUICKLOADSTATE:
|
||||
if (g_State.bEmuThreadStarted)
|
||||
{
|
||||
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
|
||||
for (int i=0; i<numCPUs; i++)
|
||||
if (disasmWindow[i])
|
||||
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
|
||||
}
|
||||
SetCursor(LoadCursor(0,IDC_WAIT));
|
||||
SaveState::LoadSlot(0, SaveStateActionFinished);
|
||||
break;
|
||||
|
||||
case ID_FILE_QUICKSAVESTATE:
|
||||
if (g_State.bEmuThreadStarted)
|
||||
{
|
||||
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
|
||||
for (int i=0; i<numCPUs; i++)
|
||||
if (disasmWindow[i])
|
||||
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
|
||||
}
|
||||
SetCursor(LoadCursor(0,IDC_WAIT));
|
||||
SaveState::SaveSlot(0, SaveStateActionFinished);
|
||||
break;
|
||||
|
||||
case ID_OPTIONS_SCREEN1X:
|
||||
SetZoom(1);
|
||||
UpdateMenus();
|
||||
|
@ -380,6 +421,10 @@ namespace MainWindow
|
|||
UpdateMenus();
|
||||
break;
|
||||
|
||||
case ID_EMULATION_RUNONLOAD:
|
||||
g_Config.bAutoRun = !g_Config.bAutoRun;
|
||||
UpdateMenus();
|
||||
break;
|
||||
//case ID_CPU_RESET:
|
||||
// MessageBox(hwndMain,"Use the controls in the disasm window for now..","Sorry",0);
|
||||
// Update();
|
||||
|
@ -503,6 +548,16 @@ namespace MainWindow
|
|||
g_Config.bFastMemory = !g_Config.bFastMemory;
|
||||
UpdateMenus();
|
||||
break;
|
||||
case ID_OPTIONS_LINEARFILTERING:
|
||||
g_Config.bLinearFiltering = !g_Config.bLinearFiltering;
|
||||
UpdateMenus();
|
||||
break;
|
||||
case ID_OPTIONS_CONTROLS:
|
||||
DialogManager::EnableAll(FALSE);
|
||||
DialogBox(hInst, (LPCTSTR)IDD_CONTROLS, hWnd, (DLGPROC)Controls);
|
||||
DialogManager::EnableAll(TRUE);
|
||||
break;
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -593,7 +648,7 @@ namespace MainWindow
|
|||
}
|
||||
else
|
||||
*/
|
||||
return DefWindowProc(hWnd,message,wParam,lParam);
|
||||
return DefWindowProc(hWnd,message,wParam,lParam);
|
||||
// case WM_LBUTTONDOWN:
|
||||
// TrackPopupMenu(menu,0,0,0,0,hWnd,0);
|
||||
// break;
|
||||
|
@ -648,6 +703,8 @@ namespace MainWindow
|
|||
CHECKITEM(ID_OPTIONS_WIREFRAME, g_Config.bDrawWireframe);
|
||||
CHECKITEM(ID_OPTIONS_HARDWARETRANSFORM, g_Config.bHardwareTransform);
|
||||
CHECKITEM(ID_OPTIONS_FASTMEMORY, g_Config.bFastMemory);
|
||||
CHECKITEM(ID_OPTIONS_LINEARFILTERING, g_Config.bLinearFiltering);
|
||||
CHECKITEM(ID_EMULATION_RUNONLOAD, g_Config.bAutoRun);
|
||||
|
||||
UINT enable = !Core_IsStepping() ? MF_GRAYED : MF_ENABLED;
|
||||
EnableMenuItem(menu,ID_EMULATION_RUN, g_State.bEmuThreadStarted ? enable : MF_GRAYED);
|
||||
|
@ -656,6 +713,10 @@ namespace MainWindow
|
|||
|
||||
enable = g_State.bEmuThreadStarted ? MF_GRAYED : MF_ENABLED;
|
||||
EnableMenuItem(menu,ID_FILE_LOAD,enable);
|
||||
EnableMenuItem(menu,ID_FILE_SAVESTATEFILE,!enable);
|
||||
EnableMenuItem(menu,ID_FILE_LOADSTATEFILE,!enable);
|
||||
EnableMenuItem(menu,ID_FILE_QUICKSAVESTATE,!enable);
|
||||
EnableMenuItem(menu,ID_FILE_QUICKLOADSTATE,!enable);
|
||||
EnableMenuItem(menu,ID_CPU_DYNAREC,enable);
|
||||
EnableMenuItem(menu,ID_CPU_INTERPRETER,enable);
|
||||
EnableMenuItem(menu,ID_CPU_FASTINTERPRETER,enable);
|
||||
|
@ -697,6 +758,53 @@ namespace MainWindow
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
const char *controllist[] = {
|
||||
"Start\tSpace",
|
||||
"Select\tV",
|
||||
"Square\tA",
|
||||
"Triangle\tS",
|
||||
"Circle\tX",
|
||||
"Cross\tZ",
|
||||
"Left Trigger\tQ",
|
||||
"Right Trigger\tW",
|
||||
"Up\tArrow Up",
|
||||
"Down\tArrow Down",
|
||||
"Left\tArrow Left",
|
||||
"Right\tArrow Right",
|
||||
"Analog Up\tI",
|
||||
"Analog Down\tK",
|
||||
"Analog Left\tJ",
|
||||
"Analog Right\tL",
|
||||
};
|
||||
// Message handler for about box.
|
||||
LRESULT CALLBACK Controls(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
W32Util::CenterWindow(hDlg);
|
||||
{
|
||||
// TODO: connect to keyboard device instead
|
||||
HWND list = GetDlgItem(hDlg, IDC_LISTCONTROLS);
|
||||
int stops[1] = {80};
|
||||
SendMessage(list, LB_SETTABSTOPS, 1, (LPARAM)stops);
|
||||
for (int i = 0; i < sizeof(controllist)/sizeof(controllist[0]); i++) {
|
||||
SendMessage(list, LB_INSERTSTRING, -1, (LPARAM)controllist[i]);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case WM_COMMAND:
|
||||
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
|
||||
{
|
||||
EndDialog(hDlg, LOWORD(wParam));
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
InvalidateRect(hwndDisplay,0,0);
|
||||
|
@ -767,12 +875,19 @@ namespace MainWindow
|
|||
}
|
||||
}
|
||||
|
||||
void SaveStateActionFinished(bool result)
|
||||
void SaveStateActionFinished(bool result, void *userdata)
|
||||
{
|
||||
// TODO: Improve messaging?
|
||||
if (!result)
|
||||
MessageBox(0, "Savestate failure. Please try again later.", "Sorry", MB_OK);
|
||||
SetCursor(LoadCursor(0, IDC_ARROW));
|
||||
|
||||
if (g_State.bEmuThreadStarted && nextState == CORE_RUNNING)
|
||||
{
|
||||
for (int i=0; i<numCPUs; i++)
|
||||
if (disasmWindow[i])
|
||||
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_GO, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void SetNextState(CoreState state)
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace MainWindow
|
|||
void SetPlaying(const char*text);
|
||||
void BrowseAndBoot();
|
||||
void SetNextState(CoreState state);
|
||||
void SaveStateActionFinished(bool result);
|
||||
void SaveStateActionFinished(bool result, void *userdata);
|
||||
void _ViewFullScreen(HWND hWnd);
|
||||
void _ViewNormal(HWND hWnd);
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ int XinputDevice::UpdateState() {
|
|||
if ( dwResult == ERROR_SUCCESS ) {
|
||||
this->ApplyDiff(state);
|
||||
Stick left = NormalizedDeadzoneFilter(state);
|
||||
__CtrlSetAnalog(left.x, -left.y);
|
||||
__CtrlSetAnalog(left.x, left.y);
|
||||
this->prevState = state;
|
||||
this->check_delay = 0;
|
||||
return 0;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "file/zip_read.h"
|
||||
|
||||
#include "../Core/Config.h"
|
||||
#include "../Core/SaveState.h"
|
||||
#include "EmuThread.h"
|
||||
|
||||
#include "LogManager.h"
|
||||
|
@ -53,8 +54,8 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
|||
|
||||
const char *fileToStart = NULL;
|
||||
const char *fileToLog = NULL;
|
||||
const char *stateToLoad = NULL;
|
||||
bool hideLog = true;
|
||||
bool autoRun = true;
|
||||
|
||||
#ifdef _DEBUG
|
||||
hideLog = false;
|
||||
|
@ -75,24 +76,32 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
|||
{
|
||||
case 'j':
|
||||
g_Config.iCpuCore = CPU_JIT;
|
||||
g_Config.bSaveSettings = false;
|
||||
break;
|
||||
case 'i':
|
||||
g_Config.iCpuCore = CPU_INTERPRETER;
|
||||
g_Config.bSaveSettings = false;
|
||||
break;
|
||||
case 'f':
|
||||
g_Config.iCpuCore = CPU_FASTINTERPRETER;
|
||||
g_Config.bSaveSettings = false;
|
||||
break;
|
||||
case 'l':
|
||||
hideLog = false;
|
||||
break;
|
||||
case 's':
|
||||
autoRun = false;
|
||||
g_Config.bAutoRun = false;
|
||||
g_Config.bSaveSettings = false;
|
||||
break;
|
||||
case '-':
|
||||
if (!strcmp(__argv[i], "--log") && i < __argc - 1)
|
||||
fileToLog = __argv[++i];
|
||||
if (!strncmp(__argv[i], "--log=", strlen("--log=")) && strlen(__argv[i]) > strlen("--log="))
|
||||
fileToLog = __argv[i] + strlen("--log=");
|
||||
if (!strcmp(__argv[i], "--state") && i < __argc - 1)
|
||||
stateToLoad = __argv[++i];
|
||||
if (!strncmp(__argv[i], "--state=", strlen("--state=")) && strlen(__argv[i]) > strlen("--state="))
|
||||
stateToLoad = __argv[i] + strlen("--state=");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -156,8 +165,8 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
|||
else
|
||||
MainWindow::BrowseAndBoot();
|
||||
|
||||
if (autoRun)
|
||||
MainWindow::SetNextState(CORE_RUNNING);
|
||||
if (fileToStart != NULL && stateToLoad != NULL)
|
||||
SaveState::Load(stateToLoad);
|
||||
|
||||
//so.. we're at the message pump of the GUI thread
|
||||
MSG msg;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue