Merge branch 'master' into mediaengine

This commit is contained in:
Henrik Rydgard 2013-01-05 16:22:08 +01:00
commit 5ba5ceff19
128 changed files with 4911 additions and 995 deletions

View file

@ -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)

View file

@ -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;
};
};

View file

@ -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,

View file

@ -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;
}
}

View file

@ -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_

View file

@ -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

View file

@ -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", &currentDirectory, "");
@ -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");
}
}

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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" />

View file

@ -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" />

View file

@ -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()

View file

@ -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);

View file

@ -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;

View file

@ -236,6 +236,7 @@ int PSPOskDialog::Update()
void PSPOskDialog::DoState(PointerWrap &p)
{
PSPDialog::DoState(p);
p.Do(oskParams);
p.Do(oskData);
p.Do(oskDesc);

View file

@ -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);

View file

@ -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*)&param->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*)&param->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*)&param->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*)&param->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*)&param->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*)&param->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");
}

View file

@ -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;
};

View file

@ -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.");
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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)
{

View file

@ -19,6 +19,8 @@
#include "../../Globals.h"
#define MISSING_KEY -10
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;}
};

View file

@ -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)
{

View file

@ -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;}
};

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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();

View file

@ -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);

View file

@ -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");
}

View file

@ -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;
}

View file

@ -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()

View file

@ -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);

View file

@ -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);
}

View file

@ -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();

View file

@ -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();

View file

@ -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"},

View file

@ -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();

View file

@ -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[] =

View file

@ -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

View file

@ -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"},

View file

@ -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)

View file

@ -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);

View file

@ -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);
}

View file

@ -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)

View file

@ -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,

View file

@ -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()

View file

@ -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);

View file

@ -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!");
}

View file

@ -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();

View file

@ -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;
}

View file

@ -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)

View file

@ -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"},

View file

@ -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 );
}

View file

@ -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;

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}
}
}

View file

@ -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);
};

View file

@ -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)

View file

@ -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();

View file

@ -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;

View file

@ -1,4 +1,5 @@
set(SRCS
GPUCommon.cpp
GPUState.cpp
Math3D.cpp
GLES/DisplayListInterpreter.cpp

View file

@ -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);
}

View file

@ -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;

View file

@ -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) {

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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();

View file

@ -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;
}

View file

@ -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; }

View file

@ -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>

View file

@ -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
View 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
View 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_;
};

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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_;
};

View file

@ -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 \

View file

@ -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

View file

@ -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;

View file

@ -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'">

View file

@ -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);

View file

@ -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)

View file

@ -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);
}

View file

@ -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;

View file

@ -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