Merge branch 'master' into framebuffer-texture

This commit is contained in:
Henrik Rydgard 2013-02-04 00:13:50 +01:00
commit 2192029486
49 changed files with 1112 additions and 500 deletions

View File

@ -148,7 +148,7 @@ void IniFile::Section::Set(const char* key, const std::vector<std::string>& newV
std::vector<std::string>::const_iterator it;
for (it = newValues.begin(); it != newValues.end(); ++it)
{
temp = (*it) + ",";
temp += (*it) + ",";
}
// remove last ,
if (temp.length())

View File

@ -20,6 +20,7 @@
#include <string>
#include <vector>
#include <map>
#include "StringUtil.h"
@ -68,12 +69,48 @@ public:
}
void Set(const char* key, const std::vector<std::string>& newValues);
template<typename U, typename V>
void Set(const char* key, const std::map<U,V>& newValues)
{
std::vector<std::string> temp;
for(typename std::map<U,V>::const_iterator it = newValues.begin(); it != newValues.end(); it++)
{
temp.push_back(ValueToString<U>(it->first)+"_"+ValueToString<V>(it->second));
}
Set(key,temp);
}
bool Get(const char* key, int* value, int defaultValue = 0);
bool Get(const char* key, u32* value, u32 defaultValue = 0);
bool Get(const char* key, bool* value, bool defaultValue = false);
bool Get(const char* key, float* value, float defaultValue = false);
bool Get(const char* key, double* value, double defaultValue = false);
bool Get(const char* key, std::vector<std::string>& values);
template<typename U, typename V>
bool Get(const char* key, std::map<U,V>& values)
{
std::vector<std::string> temp;
if(!Get(key,temp))
{
return false;
}
values.clear();
for(int i = 0; i < temp.size(); i++)
{
std::vector<std::string> key_val;
SplitString(temp[i],'_',key_val);
if(key_val.size() < 2)
continue;
U mapKey;
V mapValue;
if(!TryParse<U>(key_val[0],&mapKey))
continue;
if(!TryParse<V>(key_val[1],&mapValue))
continue;
values[mapKey] = mapValue;
}
return true;
}
bool operator < (const Section& other) const {
return name < other.name;

View File

@ -158,21 +158,24 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const
{
std::lock_guard<std::mutex> lk(m_log_lock);
char temp[MAX_MSGLEN];
char msg[MAX_MSGLEN * 2];
LogContainer *log = m_Log[type];
if (!log || !log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners())
return;
CharArrayFromFormatV(temp, MAX_MSGLEN, format, args);
static const char level_to_char[7] = "-NEWID";
char formattedTime[13];
Common::Timer::GetTimeFormatted(formattedTime);
sprintf(msg, "%s %s:%d %c[%s]: %s\n",
char *msgPos = msg;
msgPos += sprintf(msgPos, "%s %s:%d %c[%s]: ",
formattedTime,
file, line, level_to_char[(int)level],
log->GetShortName(), temp);
log->GetShortName());
msgPos += vsnprintf(msgPos, MAX_MSGLEN, format, args);
// This will include the null terminator.
memcpy(msgPos, "\n", sizeof("\n"));
log->Trigger(level, msg);
}

View File

@ -33,12 +33,6 @@
#endif
#endif
#if defined(__SYMBIAN32__)
// Also Xbox 360
#define UNUSABLE_MMAP 1
#endif
#ifdef ANDROID
// Hopefully this ABI will never change...

View File

@ -23,6 +23,11 @@
#endif
#include <string>
#if defined(__SYMBIAN32__)
// Also Xbox 360
#define UNUSABLE_MMAP 1
#endif
void* AllocateExecutableMemory(size_t size, bool low = true);
void* AllocateMemoryPages(size_t size);
void FreeMemoryPages(void* ptr, size_t size);

View File

@ -118,6 +118,14 @@ static bool TryParse(const std::string &str, N *const output)
return false;
}
template <typename N>
static std::string ValueToString(const N value)
{
std::stringstream string;
string << value;
return string.str();
}
// TODO: kill this
bool AsciiToHex(const char* _szValue, u32& result);

View File

@ -83,6 +83,7 @@ void CConfig::Load(const char *iniFileName)
false);
#endif
control->Get("LargeControls", &bLargeControls, false);
control->Get("KeyMapping",iMappingMap);
IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam");
pspConfig->Get("Language", &ilanguage, PSP_SYSTEMPARAM_LANGUAGE_ENGLISH);
@ -133,6 +134,7 @@ void CConfig::Save()
control->Set("ShowStick", bShowAnalogStick);
control->Set("ShowTouchControls", bShowTouchControls);
control->Set("LargeControls", bLargeControls);
control->Set("KeyMapping",iMappingMap);
IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam");
pspConfig->Set("Language", ilanguage);

View File

@ -18,6 +18,7 @@
#pragma once
#include <string>
#include <map>
#define PPSSPP_VERSION_STR "0.6.1"
@ -73,6 +74,9 @@ public:
bool bShowDebugStats;
bool bLargeControls;
// Control
std::map<int,int> iMappingMap; // Can be used differently depending on systems
// SystemParam
int ilanguage;
int itimeformat;

View File

@ -240,6 +240,11 @@ template<u32 func(u32, int, u32, int, int)> void WrapU_UIUII() {
RETURN(retval);
}
template<u32 func(u32, int, u32, int)> void WrapU_UIUI() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(u32, int, u32)> void WrapU_UIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);

View File

@ -377,7 +377,8 @@ inline void updateSyscallStats(int modulenum, int funcnum, double total)
void CallSyscall(u32 op)
{
time_update();
if (g_Config.bShowDebugStats)
time_update();
double start = time_now_d();
u32 callno = (op >> 6) & 0xFFFFF; //20 bits
int funcnum = callno & 0xFFF;
@ -400,7 +401,9 @@ void CallSyscall(u32 op)
{
ERROR_LOG(HLE,"Unimplemented HLE function %s", moduleDB[modulenum].funcTable[funcnum].name);
}
time_update();
if (g_Config.bShowDebugStats)
{
time_update();
updateSyscallStats(modulenum, funcnum, time_now_d() - start);
}
}

View File

@ -34,22 +34,39 @@
#define PSP_MODE_AT_3_PLUS 0x00001000
#define PSP_MODE_AT_3 0x00001001
const u32 ATRAC_MAX_SAMPLES = 1024;
struct InputBuffer {
u32 addr;
u32 size;
u32 offset;
u32 writableBytes;
u32 neededBytes;
u32 filesize;
u32 fileoffset;
};
struct Atrac {
Atrac() : decodePos(0), buffer(0), bufferSize(0), loopNum(0) {}
Atrac() : decodePos(0), decodeEnd(0), loopNum(0) {
memset(&first, 0, sizeof(first));
memset(&second, 0, sizeof(second));
}
void DoState(PointerWrap &p) {
p.Do(decodePos);
p.Do(buffer);
p.Do(bufferSize);
p.Do(decodeEnd);
p.Do(loopNum);
p.Do(first);
p.Do(second);
p.DoMarker("Atrac");
}
u32 decodePos;
u32 buffer;
u32 bufferSize;
u32 decodeEnd;
int loopNum;
InputBuffer first;
InputBuffer second;
};
std::map<int, Atrac *> atracMap;
@ -92,21 +109,6 @@ void __AtracShutdown()
atracMap.clear();
}
// Temporary workaround to prevent excessive logging making games very slow.
// This is just the default cycle / 10, so about 1/10 second.
const u64 atracLogTickFrequency = 22200;
static bool atracShouldLogUnimpl(u64 &lastTicks) {
u64 ticks = CoreTiming::GetTicks();
bool result = ticks - lastTicks >= atracLogTickFrequency;
lastTicks = ticks;
return result;
}
// Switch if you want all errors.
#define ERROR_LOG_LIMITED(t, ...) { static u64 limited__lastTicks = 0; if (atracShouldLogUnimpl(limited__lastTicks)) ERROR_LOG(t, __VA_ARGS__); }
//#define ERROR_LOG_LIMITED(t, ...) { ERROR_LOG(t, __VA_ARGS__); }
Atrac *getAtrac(int atracID) {
if (atracMap.find(atracID) == atracMap.end()) {
return NULL;
@ -139,13 +141,13 @@ int getCodecType(int addr) {
u32 sceAtracGetAtracID(int codecType)
{
ERROR_LOG_LIMITED(HLE, "FAKE sceAtracGetAtracID(%i)", codecType);
ERROR_LOG(HLE, "FAKE sceAtracGetAtracID(%i)", codecType);
return createAtrac(new Atrac);
}
u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracAddStreamData(%i, %08x)", atracID, bytesToAdd);
ERROR_LOG(HLE, "UNIMPL sceAtracAddStreamData(%i, %08x)", atracID, bytesToAdd);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -156,13 +158,13 @@ u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd)
u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishFlagAddr, u32 remainAddr)
{
ERROR_LOG_LIMITED(HLE, "FAKE sceAtracDecodeData(%i, %08x, %08x, %08x, %08x)", atracID, outAddr, numSamplesAddr, finishFlagAddr, remainAddr);
ERROR_LOG(HLE, "FAKE sceAtracDecodeData(%i, %08x, %08x, %08x, %08x)", atracID, outAddr, numSamplesAddr, finishFlagAddr, remainAddr);
Atrac *atrac = getAtrac(atracID);
u32 ret = 0;
if (atrac != NULL) {
// We already passed the end - return an error (many games check for this.)
if (atrac->decodePos >= atrac->bufferSize && atrac->loopNum == 0) {
if (atrac->decodePos >= atrac->decodeEnd && atrac->loopNum == 0) {
Memory::Write_U32(0, numSamplesAddr);
Memory::Write_U32(1, finishFlagAddr);
Memory::Write_U32(0, remainAddr);
@ -170,8 +172,10 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF
ret = ATRAC_ERROR_ALL_DATA_DECODED;
} else {
// TODO: This isn't at all right, but at least it makes the music "last" some time.
u32 numSamples = (atrac->bufferSize - atrac->decodePos) / (sizeof(s16) * 2);
if (numSamples > ATRAC_MAX_SAMPLES) {
int numSamples = (atrac->decodeEnd - atrac->decodePos) / (sizeof(s16) * 2);
if (atrac->decodePos >= atrac->decodeEnd) {
numSamples = 0;
} else if (numSamples > ATRAC_MAX_SAMPLES) {
numSamples = ATRAC_MAX_SAMPLES;
}
@ -188,13 +192,12 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF
Memory::Write_U32(numSamples, numSamplesAddr);
atrac->decodePos += ATRAC_MAX_SAMPLES;
if (numSamples == 0) {
if (numSamples < ATRAC_MAX_SAMPLES) {
Memory::Write_U32(1, finishFlagAddr);
Memory::Write_U32(-1, remainAddr);
} else {
Memory::Write_U32(0, finishFlagAddr);
Memory::Write_U32(-1, remainAddr);
}
Memory::Write_U32(-1, remainAddr);
}
// TODO: Can probably remove this after we validate no wrong ids?
} else {
@ -211,32 +214,34 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF
u32 sceAtracEndEntry()
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracEndEntry(.)");
ERROR_LOG(HLE, "UNIMPL sceAtracEndEntry(.)");
return 0;
}
u32 sceAtracGetBufferInfoForReseting(int atracID, int sample, u32 bufferInfoAddr)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracGetBufferInfoForReseting(%i, %i, %08x)",atracID, sample, bufferInfoAddr);
ERROR_LOG(HLE, "UNIMPL sceAtracGetBufferInfoForReseting(%i, %i, %08x)",atracID, sample, bufferInfoAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
// TODO: Write the right stuff instead.
Memory::Memset(bufferInfoAddr, 0, 32);
//return -1;
} else {
Memory::Write_U32(atrac->buffer, bufferInfoAddr);
Memory::Write_U32(atrac->bufferSize, bufferInfoAddr + 4);
Memory::Write_U32(0, bufferInfoAddr + 8);
Memory::Write_U32(0, bufferInfoAddr + 12);
// TODO: Write the right stuff instead.
Memory::Memset(bufferInfoAddr + 16, 0, 16);
Memory::Write_U32(atrac->first.addr, bufferInfoAddr);
Memory::Write_U32(atrac->first.writableBytes, bufferInfoAddr + 4);
Memory::Write_U32(atrac->first.neededBytes, bufferInfoAddr + 8);
Memory::Write_U32(atrac->first.fileoffset, bufferInfoAddr + 12);
Memory::Write_U32(atrac->second.addr, bufferInfoAddr + 16);
Memory::Write_U32(atrac->second.writableBytes, bufferInfoAddr + 20);
Memory::Write_U32(atrac->second.neededBytes, bufferInfoAddr + 24);
Memory::Write_U32(atrac->second.fileoffset, bufferInfoAddr + 28);
}
return 0;
}
u32 sceAtracGetBitrate(int atracID, u32 outBitrateAddr)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracGetBitrate(%i, %08x)", atracID, outBitrateAddr);
ERROR_LOG(HLE, "UNIMPL sceAtracGetBitrate(%i, %08x)", atracID, outBitrateAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -248,7 +253,7 @@ u32 sceAtracGetBitrate(int atracID, u32 outBitrateAddr)
u32 sceAtracGetChannel(int atracID, u32 channelAddr)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracGetChannel(%i, %08x)", atracID, channelAddr);
ERROR_LOG(HLE, "UNIMPL sceAtracGetChannel(%i, %08x)", atracID, channelAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -258,19 +263,25 @@ u32 sceAtracGetChannel(int atracID, u32 channelAddr)
return 0;
}
u32 sceAtracGetLoopStatus(int atracID, u32 loopNbr, u32 statusAddr)
u32 sceAtracGetLoopStatus(int atracID, u32 loopNumAddr, u32 statusAddr)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracGetLoopStatus(%i, %08x, %08x)", atracID, loopNbr, statusAddr );
ERROR_LOG(HLE, "UNIMPL sceAtracGetLoopStatus(%i, %08x, %08x)", atracID, loopNumAddr, statusAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
} else {
if (Memory::IsValidAddress(loopNumAddr))
Memory::Write_U32(atrac->loopNum, loopNumAddr);
// TODO: What does this mean?
if (Memory::IsValidAddress(statusAddr))
Memory::Write_U32(1, statusAddr);
}
return 0;
}
u32 sceAtracGetInternalErrorInfo(int atracID, u32 errorAddr)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracGetInternalErrorInfo(%i, %08x)", atracID, errorAddr);
ERROR_LOG(HLE, "UNIMPL sceAtracGetInternalErrorInfo(%i, %08x)", atracID, errorAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -282,7 +293,7 @@ u32 sceAtracGetInternalErrorInfo(int atracID, u32 errorAddr)
u32 sceAtracGetMaxSample(int atracID, u32 maxSamplesAddr)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracGetMaxSample(%i, %08x)", atracID, maxSamplesAddr);
ERROR_LOG(HLE, "UNIMPL sceAtracGetMaxSample(%i, %08x)", atracID, maxSamplesAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -294,7 +305,7 @@ u32 sceAtracGetMaxSample(int atracID, u32 maxSamplesAddr)
u32 sceAtracGetNextDecodePosition(int atracID, u32 outposAddr)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracGetNextDecodePosition(%i, %08x)", atracID, outposAddr);
ERROR_LOG(HLE, "UNIMPL sceAtracGetNextDecodePosition(%i, %08x)", atracID, outposAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -305,17 +316,19 @@ u32 sceAtracGetNextDecodePosition(int atracID, u32 outposAddr)
u32 sceAtracGetNextSample(int atracID, u32 outNAddr)
{
ERROR_LOG_LIMITED(HLE, "FAKE sceAtracGetNextSample(%i, %08x)", atracID, outNAddr);
ERROR_LOG(HLE, "FAKE sceAtracGetNextSample(%i, %08x)", atracID, outNAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
Memory::Write_U32(1, outNAddr);
} else {
if (atrac->decodePos >= atrac->bufferSize) {
if (atrac->decodePos >= atrac->decodeEnd) {
Memory::Write_U32(0, outNAddr);
} else {
// TODO: This is not correct.
u32 numSamples = (atrac->bufferSize - atrac->decodePos) / (sizeof(s16) * 2);
u32 numSamples = (atrac->decodeEnd - atrac->decodePos) / (sizeof(s16) * 2);
if (numSamples > ATRAC_MAX_SAMPLES)
numSamples = ATRAC_MAX_SAMPLES;
Memory::Write_U32(numSamples, outNAddr);
}
}
@ -324,7 +337,7 @@ u32 sceAtracGetNextSample(int atracID, u32 outNAddr)
u32 sceAtracGetRemainFrame(int atracID, u32 remainAddr)
{
ERROR_LOG_LIMITED(HLE, "sceAtracGetRemainFrame(%i, %08x)", atracID, remainAddr);
ERROR_LOG(HLE, "sceAtracGetRemainFrame(%i, %08x)", atracID, remainAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -337,7 +350,7 @@ u32 sceAtracGetRemainFrame(int atracID, u32 remainAddr)
u32 sceAtracGetSecondBufferInfo(int atracID, u32 outposAddr, u32 outBytesAddr)
{
ERROR_LOG_LIMITED(HLE, "sceAtracGetSecondBufferInfo(%i, %08x, %08x)", atracID, outposAddr, outBytesAddr);
ERROR_LOG(HLE, "sceAtracGetSecondBufferInfo(%i, %08x, %08x)", atracID, outposAddr, outBytesAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -349,7 +362,7 @@ u32 sceAtracGetSecondBufferInfo(int atracID, u32 outposAddr, u32 outBytesAddr)
u32 sceAtracGetSoundSample(int atracID, u32 outEndSampleAddr, u32 outLoopStartSampleAddr, u32 outLoopEndSampleAddr)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracGetSoundSample(%i, %08x, %08x, %08x)", atracID, outEndSampleAddr, outLoopStartSampleAddr, outLoopEndSampleAddr);
ERROR_LOG(HLE, "UNIMPL sceAtracGetSoundSample(%i, %08x, %08x, %08x)", atracID, outEndSampleAddr, outLoopStartSampleAddr, outLoopEndSampleAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -360,29 +373,29 @@ u32 sceAtracGetSoundSample(int atracID, u32 outEndSampleAddr, u32 outLoopStartSa
return 0;
}
u32 sceAtracGetStreamDataInfo(int atracID, u32 writePointerAddr, u32 availableBytesAddr, u32 readOffsetAddr)
u32 sceAtracGetStreamDataInfo(int atracID, u32 writeAddr, u32 writableBytesAddr, u32 readOffsetAddr)
{
ERROR_LOG_LIMITED(HLE, "FAKE sceAtracGetStreamDataInfo(%i, %08x, %08x, %08x)", atracID, writePointerAddr, availableBytesAddr, readOffsetAddr);
ERROR_LOG(HLE, "FAKE sceAtracGetStreamDataInfo(%i, %08x, %08x, %08x)", atracID, writeAddr, writableBytesAddr, readOffsetAddr);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
}
Memory::Write_U32(atrac ? atrac->buffer : 0, readOffsetAddr);
Memory::Write_U32(0, availableBytesAddr);
Memory::Write_U32(0, writePointerAddr);
Memory::Write_U32(atrac->first.addr, writeAddr);
Memory::Write_U32(atrac->first.writableBytes, writableBytesAddr);
Memory::Write_U32(atrac->first.fileoffset, readOffsetAddr);
return 0;
}
u32 sceAtracReleaseAtracID(int atracID)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracReleaseAtracID(%i)", atracID);
ERROR_LOG(HLE, "UNIMPL sceAtracReleaseAtracID(%i)", atracID);
deleteAtrac(atracID);
return 0;
}
u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracResetPlayPosition(%i, %i, %i, %i)", atracID, sample, bytesWrittenFirstBuf, bytesWrittenSecondBuf);
ERROR_LOG(HLE, "UNIMPL sceAtracResetPlayPosition(%i, %i, %i, %i)", atracID, sample, bytesWrittenFirstBuf, bytesWrittenSecondBuf);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -395,7 +408,7 @@ u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFirstBuf,
u32 sceAtracSetHalfwayBuffer(int atracID, u32 halfBuffer, u32 readSize, u32 halfBufferSize)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracSetHalfwayBuffer(%i, %08x, %8x, %8x)", atracID, halfBuffer, readSize, halfBufferSize);
ERROR_LOG(HLE, "UNIMPL sceAtracSetHalfwayBuffer(%i, %08x, %8x, %8x)", atracID, halfBuffer, readSize, halfBufferSize);
return 0;
}
@ -411,46 +424,52 @@ u32 sceAtracSetSecondBuffer(int atracID, u32 secondBuffer, u32 secondBufferSize)
u32 sceAtracSetData(int atracID, u32 buffer, u32 bufferSize)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracSetData(%i, %08x, %08x)", atracID, buffer, bufferSize);
ERROR_LOG(HLE, "UNIMPL sceAtracSetData(%i, %08x, %08x)", atracID, buffer, bufferSize);
Atrac *atrac = getAtrac(atracID);
if (atrac != NULL) {
atrac->buffer = buffer;
atrac->bufferSize = bufferSize;
atrac->first.addr = buffer;
atrac->first.size = bufferSize;
// TODO: This is an ugly approximation of song length.
atrac->decodeEnd = bufferSize * 3;
}
return 0;
}
int sceAtracSetDataAndGetID(u32 buffer, u32 bufferSize)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracSetDataAndGetID(%08x, %08x)", buffer, bufferSize);
ERROR_LOG(HLE, "UNIMPL sceAtracSetDataAndGetID(%08x, %08x)", buffer, bufferSize);
int codecType = getCodecType(buffer);
Atrac *atrac = new Atrac();
atrac->buffer = buffer;
atrac->bufferSize = bufferSize;
atrac->first.addr = buffer;
atrac->first.size = bufferSize;
// TODO: This is an ugly approximation of song length.
atrac->decodeEnd = bufferSize * 3;
return createAtrac(atrac);
}
int sceAtracSetHalfwayBufferAndGetID(int atracID, u32 halfBuffer, u32 readSize, u32 halfBufferSize)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracSetHalfwayBufferAndGetID(%i, %08x, %08x, %08x)", atracID, halfBuffer, readSize, halfBufferSize);
ERROR_LOG(HLE, "UNIMPL sceAtracSetHalfwayBufferAndGetID(%i, %08x, %08x, %08x)", atracID, halfBuffer, readSize, halfBufferSize);
int codecType = getCodecType(halfBuffer);
Atrac *atrac = new Atrac();
atrac->buffer = halfBuffer;
atrac->bufferSize = halfBufferSize;
atrac->first.addr = halfBuffer;
atrac->first.size = halfBufferSize;
// TODO: This is an ugly approximation of song length.
atrac->decodeEnd = halfBufferSize * 3;
return createAtrac(atrac);
}
u32 sceAtracStartEntry()
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracStartEntry(.)");
ERROR_LOG(HLE, "UNIMPL sceAtracStartEntry(.)");
return 0;
}
u32 sceAtracSetLoopNum(int atracID, int loopNum)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracSetLoopNum(%i, %i)", atracID, loopNum);
ERROR_LOG(HLE, "UNIMPL sceAtracSetLoopNum(%i, %i)", atracID, loopNum);
Atrac *atrac = getAtrac(atracID);
if (atrac) {
atrac->loopNum = loopNum;
@ -460,13 +479,13 @@ u32 sceAtracSetLoopNum(int atracID, int loopNum)
int sceAtracReinit()
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracReinit(..)");
ERROR_LOG(HLE, "UNIMPL sceAtracReinit(..)");
return 0;
}
int sceAtracGetOutputChannel(int atracID, u32 outputChanPtr)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracGetOutputChannel(%i, %08x)", atracID, outputChanPtr);
ERROR_LOG(HLE, "UNIMPL sceAtracGetOutputChannel(%i, %08x)", atracID, outputChanPtr);
if (Memory::IsValidAddress(outputChanPtr))
Memory::Write_U32(2, outputChanPtr);
return 0;
@ -474,7 +493,7 @@ int sceAtracGetOutputChannel(int atracID, u32 outputChanPtr)
int sceAtracIsSecondBufferNeeded(int atracID)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracIsSecondBufferNeeded(%i)", atracID);
ERROR_LOG(HLE, "UNIMPL sceAtracIsSecondBufferNeeded(%i)", atracID);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -484,7 +503,7 @@ int sceAtracIsSecondBufferNeeded(int atracID)
int sceAtracSetMOutHalfwayBuffer(int atracID, u32 MOutHalfBuffer, int readSize, int MOutHalfBufferSize)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracSetMOutHalfwayBuffer(%i, %08x, %i, %i)", atracID, MOutHalfBuffer, readSize, MOutHalfBufferSize);
ERROR_LOG(HLE, "UNIMPL sceAtracSetMOutHalfwayBuffer(%i, %08x, %i, %i)", atracID, MOutHalfBuffer, readSize, MOutHalfBufferSize);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
@ -494,15 +513,39 @@ int sceAtracSetMOutHalfwayBuffer(int atracID, u32 MOutHalfBuffer, int readSize,
int sceAtracSetAA3DataAndGetID(u32 buffer, int bufferSize, int fileSize, u32 metadataSizeAddr)
{
ERROR_LOG_LIMITED(HLE, "UNIMPL sceAtracSetAA3DataAndGetID(%08x, %i, %i, %08x)", buffer, bufferSize, fileSize, metadataSizeAddr);
ERROR_LOG(HLE, "UNIMPL sceAtracSetAA3DataAndGetID(%08x, %i, %i, %08x)", buffer, bufferSize, fileSize, metadataSizeAddr);
int codecType = getCodecType(buffer);
Atrac *atrac = new Atrac();
atrac->buffer = buffer;
atrac->bufferSize = bufferSize;
atrac->first.addr = buffer;
atrac->first.size = bufferSize;
// TODO: This is an ugly approximation of song length.
atrac->decodeEnd = bufferSize * 3;
return createAtrac(atrac);
}
int _sceAtracGetContextAddress(int atracID)
{
ERROR_LOG(HLE, "UNIMPL _sceAtracGetContextAddress(%i)", atracID);
Atrac *atrac = getAtrac(atracID);
if (!atrac) {
//return -1;
}
return 0;
}
int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr)
{
ERROR_LOG(HLE, "UNIMPL sceAtracLowLevelInitDecoder(%i, %08x)", atracID, paramsAddr);
return 0;
}
int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesConsumedAddr, u32 samplesAddr, u32 sampleBytesAddr)
{
ERROR_LOG(HLE, "UNIMPL sceAtracLowLevelDecode(%i, %i, %08x, %08x, %08x, %08x)", atracID, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr);
return 0;
}
const HLEFunction sceAtrac3plus[] =
{
{0x7db31251,WrapU_IU<sceAtracAddStreamData>,"sceAtracAddStreamData"},
@ -540,7 +583,9 @@ const HLEFunction sceAtrac3plus[] =
{0x9CD7DE03,0,"sceAtracSetMOutHalfwayBufferAndGetID"},
{0x5622B7C1,WrapI_UIIU<sceAtracSetAA3DataAndGetID>,"sceAtracSetAA3DataAndGetID"},
{0x5DD66588,0,"sceAtracSetAA3HalfwayBufferAndGetID"},
{0x231FC6B7,0,"_sceAtracGetContextAddress"},
{0x231FC6B7,WrapI_I<_sceAtracGetContextAddress>,"_sceAtracGetContextAddress"},
{0x1575D64B,WrapI_IU<sceAtracLowLevelInitDecoder>,"sceAtracLowLevelInitDecoder"},
{0x0C116E1B,WrapI_IUUUU<sceAtracLowLevelDecode>,"sceAtracLowLevelDecode"},
};

View File

@ -182,8 +182,8 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
}
vblankWaitingThreads.clear();
// Trigger VBlank interrupt handlers.
__TriggerInterrupt(PSP_INTR_IMMEDIATE | PSP_INTR_ONLY_IF_ENABLED, PSP_VBLANK_INTR);
// Trigger VBlank interrupt handlers - and resched even if there's none registered.
__TriggerInterrupt(PSP_INTR_IMMEDIATE | PSP_INTR_ONLY_IF_ENABLED | PSP_INTR_ALWAYS_RESCHED, PSP_VBLANK_INTR);
CoreTiming::ScheduleEvent(msToCycles(vblankMs) - cyclesLate, leaveVblankEvent, vbCount+1);

View File

@ -601,10 +601,11 @@ const HLEFunction ThreadManForUser[] =
{0x94416130,WrapU_UUUU<sceKernelGetThreadmanIdList>,"sceKernelGetThreadmanIdList"},
{0x57CF62DD,WrapU_U<sceKernelGetThreadmanIdType>,"sceKernelGetThreadmanIdType"},
{0xBC80EC7C,WrapU_UUUU<sceKernelExtendThreadStack>, "sceKernelExtendThreadStack"},
{0x82BC5777,sceKernelGetSystemTimeWide,"sceKernelGetSystemTimeWide"},
{0xdb738f35,sceKernelGetSystemTime,"sceKernelGetSystemTime"},
{0x369ed59d,sceKernelGetSystemTimeLow,"sceKernelGetSystemTimeLow"},
{0x82BC5777,WrapU64_V<sceKernelGetSystemTimeWide>,"sceKernelGetSystemTimeWide"},
{0xdb738f35,WrapI_U<sceKernelGetSystemTime>,"sceKernelGetSystemTime"},
{0x369ed59d,WrapU_V<sceKernelGetSystemTimeLow>,"sceKernelGetSystemTimeLow"},
{0x8218B4DD,&WrapU_U<sceKernelReferGlobalProfiler>,"sceKernelReferGlobalProfiler"},
{0x627E6F3A,&WrapU_U<sceKernelReferSystemStatus>,"sceKernelReferSystemStatus"},
@ -616,12 +617,11 @@ const HLEFunction ThreadManForUser[] =
{0x7e65b999,WrapI_I<sceKernelCancelAlarm>,"sceKernelCancelAlarm"},
{0xDAA3F564,WrapI_IU<sceKernelReferAlarmStatus>,"sceKernelReferAlarmStatus"},
{0xba6b92e2,sceKernelSysClock2USec,"sceKernelSysClock2USec"},
{0x110DEC9A,0,"sceKernelUSec2SysClock"},
{0xC8CD158C,WrapU_U<sceKernelUSec2SysClockWide>,"sceKernelUSec2SysClockWide"},
{0xE1619D7C,sceKernelSysClock2USecWide,"sceKernelSysClock2USecWide"},
{0xba6b92e2,WrapI_UUU<sceKernelSysClock2USec>,"sceKernelSysClock2USec"},
{0x110dec9a,WrapI_UU<sceKernelUSec2SysClock>,"sceKernelUSec2SysClock"},
{0xC8CD158C,WrapU64_U<sceKernelUSec2SysClockWide>,"sceKernelUSec2SysClockWide"},
{0xE1619D7C,WrapI_UUUU<sceKernelSysClock2USecWide>,"sceKernelSysClock2USecWide"},
{0x110dec9a,sceKernelUSec2SysClock,"sceKernelUSec2SysClock"},
{0x278C0DF5,WrapI_IU<sceKernelWaitThreadEnd>,"sceKernelWaitThreadEnd"},
{0xd59ead2f,sceKernelWakeupThread,"sceKernelWakeupThread"}, //AI Go, audio?

View File

@ -386,6 +386,11 @@ void __TriggerRunInterrupts(int type)
{
if ((type & PSP_INTR_HLE) != 0)
hleRunInterrupts();
else if ((type & PSP_INTR_ALWAYS_RESCHED) != 0)
{
if (!__RunOnePendingInterrupt())
__KernelSwitchOffThread("interrupt");
}
else
__RunOnePendingInterrupt();
}

View File

@ -63,6 +63,9 @@ enum PSPInterruptTriggerType {
PSP_INTR_HLE = 0x1,
// Only trigger (as above) if interrupts are not suspended.
PSP_INTR_ONLY_IF_ENABLED = 0x2,
// Always reschedule, even if there's no handler registered.
// TODO: Maybe this should just always do this? Not sure.
PSP_INTR_ALWAYS_RESCHED = 0x4,
};
struct PendingInterrupt {

View File

@ -64,14 +64,17 @@ static const char *blacklistedModules[] = {
"sceATRAC3plus_Library",
"sceFont_Library",
"SceFont_Library",
"SceHttp_Library",
"sceMpeg_library",
"sceNetAdhocctl_Library",
"sceNetAdhocDownload_Library",
"sceNetAdhocMatching_Library",
"sceNetApDialogDummy_Library",
"sceNetAdhoc_Library",
"sceNetApctl_Library",
"sceNetInet_Library",
"sceNetResolver_Library",
"sceNet_Library",
"sceMpeg_library",
};
struct NativeModule {
@ -826,25 +829,35 @@ void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValu
RETURN(error);
return;
} else if (module->isFake) {
INFO_LOG(HLE,"sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): faked (undecryptable module)",
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)",
WARN_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;
// attr = module->nm
if (entryAddr == -1 || entryAddr == module->memoryBlockAddr - 1) {
// TODO: Do these always take effect, or do they not override optionAddr?
if (module->nm.module_start_func != 0 && module->nm.module_start_func != -1) {
entryAddr = module->nm.module_start_func;
priority = module->nm.module_start_thread_priority;
attr = module->nm.module_start_thread_attr;
stacksize = module->nm.module_start_thread_stacksize;
} else {
// TODO: Fix, check return value? Or do we call nothing?
RETURN(moduleId);
return;
}
}
SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, entryAddr, priority, stacksize, attr, 0);
sceKernelStartThread(threadID, argsize, argAddr);
// TODO: This will probably return the wrong value?
sceKernelWaitThreadEnd(threadID, 0);
}
//SceUID threadId;
//__KernelCreateThread(threadId, moduleId, module->nm.name, module->nm.entry_addr, priority, stacksize, attr);
// Apparently, we need to call the entry point directly and insert the return value afterwards. This calls
// for a MipsCall and an Action. TODO
RETURN(moduleId); // TODO: Delete
// TODO: Is this the correct return value?
RETURN(moduleId);
}
void sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 returnValueAddr, u32 optionAddr)
@ -868,6 +881,12 @@ u32 sceKernelUnloadModule(u32 moduleId)
return 0;
}
u32 sceKernelStopUnloadSelfModuleWithStatus(u32 moduleId, u32 argSize, u32 argp, u32 statusAddr, u32 optionAddr)
{
ERROR_LOG(HLE,"UNIMPL sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x,)", moduleId, argSize, argp, statusAddr, optionAddr);
return 0;
}
u32 sceKernelGetModuleIdByAddress(u32 moduleAddr)
{
ERROR_LOG(HLE,"HACKIMPL sceKernelGetModuleIdByAddress(%08x)", PARAM(0));
@ -989,7 +1008,7 @@ const HLEFunction ModuleMgrForUser[] =
{0x748CBED9,WrapU_UU<sceKernelQueryModuleInfo>,"sceKernelQueryModuleInfo"},
{0xd8b73127,&WrapU_U<sceKernelGetModuleIdByAddress>, "sceKernelGetModuleIdByAddress"},
{0xf0a26395,WrapU_V<sceKernelGetModuleId>, "sceKernelGetModuleId"},
{0x8f2df740,0,"sceKernelStopUnloadSelfModuleWithStatus"},
{0x8f2df740,WrapU_UUUUU<sceKernelStopUnloadSelfModuleWithStatus>,"sceKernelStopUnloadSelfModuleWithStatus"},
{0xfef27dc1,&WrapU_CU<sceKernelLoadModuleDNAS> , "sceKernelLoadModuleDNAS"},
};

View File

@ -231,12 +231,17 @@ private:
class ActionAfterMipsCall : public Action
{
ActionAfterMipsCall()
{
chainedAction = NULL;
}
public:
virtual void run(MipsCall &call);
static Action *Create()
{
return new ActionAfterMipsCall;
return new ActionAfterMipsCall();
}
virtual void DoState(PointerWrap &p)
@ -392,11 +397,11 @@ public:
ThreadWaitInfo getWaitInfo();
// Utils
bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
virtual void DoState(PointerWrap &p)
{
@ -465,9 +470,14 @@ u32 idleThreadHackAddr;
u32 threadReturnHackAddr;
u32 cbReturnHackAddr;
u32 intReturnHackAddr;
std::vector<SceUID> threadqueue;
std::vector<ThreadCallback> threadEndListeners;
typedef std::vector<SceUID> ThreadList;
// Lists all thread ids that aren't deleted/etc.
ThreadList threadqueue;
// Lists only ready thread ids.
std::map<u32, ThreadList> threadReadyQueue;
SceUID threadIdleID[2];
int eventScheduledWakeup;
@ -512,7 +522,6 @@ void MipsCall::DoState(PointerWrap &p)
p.Do(savedPc);
p.Do(savedV0);
p.Do(savedV1);
p.Do(returnVoid);
p.Do(tag);
p.Do(savedId);
p.Do(reschedAfter);
@ -621,6 +630,29 @@ void __KernelThreadingDoState(PointerWrap &p)
p.Do(dispatchEnabled);
p.Do(curModule);
int n = (int) threadReadyQueue.size();
p.Do(n);
if (p.mode == p.MODE_READ)
{
threadReadyQueue.clear();
for (int i = 0; i < n; ++i)
{
u32 prio;
p.Do(prio);
ThreadList threads;
p.Do(threads, dv);
threadReadyQueue[prio] = threads;
}
}
else
{
for (auto it = threadReadyQueue.begin(), end = threadReadyQueue.end(); it != end; ++it)
{
p.Do(it->first);
p.Do(it->second, dv);
}
}
p.Do(eventScheduledWakeup);
CoreTiming::RestoreRegisterEvent(eventScheduledWakeup, "ScheduledWakeup", &hleScheduledWakeup);
p.Do(eventThreadEndTimeout);
@ -664,6 +696,43 @@ void __KernelFireThreadEnd(SceUID threadID)
}
}
// TODO: Use __KernelChangeThreadState instead? It has other affects...
void __KernelChangeReadyState(Thread *thread, SceUID threadID, bool ready, bool atStart = false)
{
int prio = thread->nt.currentPriority;
if (thread->isReady())
{
if (!ready)
threadReadyQueue[prio].erase(std::remove(threadReadyQueue[prio].begin(), threadReadyQueue[prio].end(), threadID), threadReadyQueue[prio].end());
}
else if (ready)
{
if (atStart)
{
size_t oldSize = threadReadyQueue[prio].size();
threadReadyQueue[prio].resize(oldSize + 1);
if (oldSize > 0)
memmove(&threadReadyQueue[prio][1], &threadReadyQueue[prio][0], oldSize * sizeof(SceUID));
threadReadyQueue[prio][0] = threadID;
}
else
threadReadyQueue[prio].push_back(threadID);
}
thread->nt.status = THREADSTATUS_READY;
}
void __KernelChangeReadyState(SceUID threadID, bool ready)
{
u32 error;
Thread *thread = kernelObjects.Get<Thread>(threadID, error);
if (thread)
__KernelChangeReadyState(thread, threadID, ready);
else
WARN_LOG(HLE, "Trying to change the ready state of an unknown thread?");
}
void __KernelStartIdleThreads()
{
for (int i = 0; i < 2; i++)
@ -673,7 +742,7 @@ void __KernelStartIdleThreads()
t->nt.gpreg = __KernelGetModuleGP(curModule);
t->context.r[MIPS_REG_GP] = t->nt.gpreg;
//t->context.pc += 4; // ADJUSTPC
t->nt.status = THREADSTATUS_READY;
__KernelChangeReadyState(t, threadIdleID[i], true);
}
}
@ -686,6 +755,10 @@ bool __KernelSwitchOffThread(const char *reason)
if (threadID != threadIdleID[0] && threadID != threadIdleID[1])
{
Thread *current = __GetCurrentThread();
if (current && current->isRunning())
__KernelChangeReadyState(current, threadID, true);
u32 error;
// Idle 0 chosen entirely arbitrarily.
Thread *t = kernelObjects.Get<Thread>(threadIdleID[0], error);
@ -714,7 +787,11 @@ void __KernelIdle()
u32 error;
Thread *t = kernelObjects.Get<Thread>(currentCallbackThreadID, error);
if (t)
{
__KernelChangeReadyState(t, currentCallbackThreadID, false);
t->nt.status = (t->nt.status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
__KernelSwitchContext(t, "idle");
}
else
{
WARN_LOG(HLE, "UNTESTED - Callback thread deleted during interrupt?");
@ -733,6 +810,7 @@ void __KernelThreadingShutdown()
{
kernelMemory.Free(threadReturnHackAddr);
threadqueue.clear();
threadReadyQueue.clear();
threadEndListeners.clear();
mipsCalls.clear();
threadReturnHackAddr = 0;
@ -1090,15 +1168,11 @@ void __KernelCancelThreadEndTimeout(SceUID threadID)
void __KernelRemoveFromThreadQueue(SceUID threadID)
{
for (size_t i = 0; i < threadqueue.size(); i++)
{
if (threadqueue[i] == threadID)
{
DEBUG_LOG(HLE, "Deleted thread %08x (%i) from thread queue", threadID, threadID);
threadqueue.erase(threadqueue.begin() + i);
return;
}
}
int prio = __KernelGetThreadPrio(threadID);
if (prio != 0)
threadReadyQueue[prio].erase(std::remove(threadReadyQueue[prio].begin(), threadReadyQueue[prio].end(), threadID), threadReadyQueue[prio].end());
threadqueue.erase(std::remove(threadqueue.begin(), threadqueue.end(), threadID), threadqueue.end());
}
u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason, bool dontSwitch)
@ -1128,46 +1202,30 @@ u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason, bo
}
Thread *__KernelNextThread() {
// round-robin scheduler
// seems to work ?
// not accurate!
int bestthread = -1;
int prio = 0xffffff;
int next = 0;
for (size_t i = 0; i < threadqueue.size(); i++)
SceUID bestThread = -1;
// This goes in priority order.
for (auto it = threadReadyQueue.begin(), end = threadReadyQueue.end(); it != end; ++it)
{
if (currentThread == threadqueue[i])
if (!it->second.empty())
{
next = (int)i;
bestThread = it->second[0];
break;
}
}
u32 error;
for (size_t i = 0; i < threadqueue.size(); i++)
{
next = (next + 1) % threadqueue.size();
Thread *t = kernelObjects.Get<Thread>(threadqueue[next], error);
if (t && t->nt.currentPriority < prio)
{
if (t->nt.status & THREADSTATUS_READY)
{
bestthread = next;
prio = t->nt.currentPriority;
}
}
}
if (bestthread != -1)
return kernelObjects.Get<Thread>(threadqueue[bestthread], error);
if (bestThread != -1)
return kernelObjects.Get<Thread>(bestThread, error);
else
return 0;
}
void __KernelReSchedule(const char *reason)
{
// TODO: Not sure if this is correct?
if (__GetCurrentThread() && __GetCurrentThread()->isRunning())
__KernelChangeReadyState(currentThread, true);
// cancel rescheduling when in interrupt or callback, otherwise everything will be fucked up
if (__IsInInterrupt() || __KernelInCallback())
{
@ -1344,7 +1402,7 @@ void __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int pr
__KernelResetThread(thread);
currentThread = id;
thread->nt.status = THREADSTATUS_READY; // do not schedule
__KernelChangeReadyState(thread, id, true); // do not schedule
strcpy(thread->nt.name, "root");
@ -1357,8 +1415,7 @@ void __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int pr
Memory::Write_U8(argp[i], location + i);
}
int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr)
int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr)
{
if (threadName == NULL)
{
@ -1382,13 +1439,21 @@ int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stack
attr |= PSP_THREAD_ATTR_USER;
SceUID id;
__KernelCreateThread(id, curModule, threadName, entry, prio, stacksize, attr);
__KernelCreateThread(id, moduleID, threadName, entry, prio, stacksize, attr);
INFO_LOG(HLE, "%i = sceKernelCreateThread(name=\"%s\", entry=%08x, prio=%x, stacksize=%i)", id, threadName, entry, prio, stacksize);
if (optionAddr != 0)
WARN_LOG(HLE, "sceKernelCreateThread(name=\"%s\"): unsupported options parameter %08x", threadName, optionAddr);
return id;
}
int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr)
{
SceUID moduleId = curModule;
if (__GetCurrentThread())
moduleId = __GetCurrentThread()->moduleId;
return __KernelCreateThread(threadName, moduleId, entry, prio, stacksize, attr, optionAddr);
}
// int sceKernelStartThread(SceUID threadToStartID, SceSize argSize, void *argBlock)
int sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr)
@ -1414,8 +1479,8 @@ int sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr)
threadToStartID,argSize,argBlockPtr);
__KernelResetThread(startThread);
__KernelChangeReadyState(startThread, threadToStartID, true, true);
startThread->nt.status = THREADSTATUS_READY;
u32 sp = startThread->context.r[MIPS_REG_SP];
if (argBlockPtr && argSize > 0)
{
@ -1493,11 +1558,10 @@ void __KernelReturnFromThread()
}
thread->nt.exitStatus = currentMIPS->r[2];
__KernelChangeReadyState(thread, currentThread, false);
thread->nt.status = THREADSTATUS_DORMANT;
__KernelFireThreadEnd(thread->GetUID());
// TODO: Need to remove the thread from any ready queues.
__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread(), thread->nt.exitStatus, "thread returned", true);
hleReSchedule("thread returned");
@ -1510,6 +1574,7 @@ void sceKernelExitThread()
_dbg_assert_msg_(HLE, thread != NULL, "Exited from a NULL thread.");
ERROR_LOG(HLE,"sceKernelExitThread FAKED");
__KernelChangeReadyState(thread, currentThread, false);
thread->nt.status = THREADSTATUS_DORMANT;
thread->nt.exitStatus = PARAM(0);
__KernelFireThreadEnd(thread->GetUID());
@ -1544,6 +1609,7 @@ void sceKernelExitDeleteThread()
if (t)
{
INFO_LOG(HLE,"sceKernelExitDeleteThread()");
__KernelChangeReadyState(t, threadHandle, false);
t->nt.status = THREADSTATUS_DORMANT;
t->nt.exitStatus = PARAM(0);
error = __KernelDeleteThread(threadHandle, PARAM(0), "thread exited with delete", true);
@ -1584,7 +1650,6 @@ int sceKernelDeleteThread(int threadHandle)
{
if (threadHandle != currentThread)
{
//TODO: remove from threadqueue!
DEBUG_LOG(HLE,"sceKernelDeleteThread(%i)",threadHandle);
u32 error;
@ -1609,7 +1674,6 @@ int sceKernelTerminateDeleteThread(int threadno)
{
if (threadno != currentThread)
{
//TODO: remove from threadqueue!
INFO_LOG(HLE, "sceKernelTerminateDeleteThread(%i)", threadno);
u32 error;
@ -1644,6 +1708,7 @@ int sceKernelTerminateThread(u32 threadID)
if (t)
{
t->nt.exitStatus = SCE_KERNEL_ERROR_THREAD_TERMINATED;
__KernelChangeReadyState(t, threadID, false);
t->nt.status = THREADSTATUS_DORMANT;
__KernelFireThreadEnd(threadID);
// TODO: Should this really reschedule?
@ -1710,7 +1775,15 @@ void sceKernelChangeThreadPriority()
if (thread)
{
DEBUG_LOG(HLE,"sceKernelChangeThreadPriority(%i, %i)", id, PARAM(1));
int prio = thread->nt.currentPriority;
threadReadyQueue[prio].erase(std::remove(threadReadyQueue[prio].begin(), threadReadyQueue[prio].end(), id), threadReadyQueue[prio].end());
thread->nt.currentPriority = PARAM(1);
if (thread->isReady())
threadReadyQueue[thread->nt.currentPriority].push_back(id);
RETURN(0);
}
else
@ -2056,6 +2129,12 @@ void sceKernelGetCallbackCount()
}
}
u32 sceKernelExtendThreadStack(u32 cpu, u32 size, u32 entryAddr, u32 entryParameter)
{
ERROR_LOG(HLE,"UNIMPL sceKernelExtendThreadStack(%08x, %08x, %08x, %08x)", cpu, size, entryAddr, entryParameter);
return 0;
}
void sceKernelReferCallbackStatus()
{
SceUID cbId = PARAM(0);
@ -2078,6 +2157,7 @@ void ActionAfterMipsCall::run(MipsCall &call) {
u32 error;
Thread *thread = kernelObjects.Get<Thread>(threadID, error);
if (thread) {
__KernelChangeReadyState(thread, threadID, (status & THREADSTATUS_READY) != 0);
thread->nt.status = status;
thread->nt.waitType = waitType;
thread->nt.waitID = waitID;
@ -2150,7 +2230,7 @@ void Thread::resumeFromWait()
this->nt.status &= ~THREADSTATUS_WAIT;
// TODO: What if DORMANT or DEAD?
if (!(this->nt.status & THREADSTATUS_WAITSUSPEND))
this->nt.status = THREADSTATUS_READY;
__KernelChangeReadyState(this, this->GetUID(), true);
// Non-waiting threads do not process callbacks.
this->isProcessingCallbacks = false;
@ -2215,13 +2295,29 @@ void __KernelSwitchContext(Thread *target, const char *reason)
// Profile on Windows shows this takes time, skip it.
if (DEBUG_LEVEL <= MAX_LOGLEVEL)
oldName = cur->GetName();
if (cur->isRunning())
{
__KernelChangeReadyState(cur, oldUID, false);
cur->nt.status = (cur->nt.status | THREADSTATUS_READY) & ~THREADSTATUS_RUNNING;
}
}
currentThread = target->GetUID();
if (target && target->isRunning())
__KernelChangeReadyState(target, currentThread, true);
__KernelLoadContext(&target->context);
DEBUG_LOG(HLE,"Context switched: %s -> %s (%s) (%i - pc: %08x -> %i - pc: %08x)",
oldName, target->GetName(),
reason,
oldUID, oldPC, target->GetUID(), currentMIPS->pc);
bool fromIdle = oldUID == threadIdleID[0] || oldUID == threadIdleID[1];
bool toIdle = currentThread == threadIdleID[0] || currentThread == threadIdleID[1];
if (!(fromIdle && toIdle))
{
DEBUG_LOG(HLE,"Context switched: %s -> %s (%s) (%i - pc: %08x -> %i - pc: %08x)",
oldName, target->GetName(),
reason,
oldUID, oldPC, currentThread, currentMIPS->pc);
}
// No longer waiting.
target->nt.waitType = WAITTYPE_NONE;
@ -2242,6 +2338,7 @@ void __KernelChangeThreadState(Thread *thread, ThreadStatus newStatus) {
// TODO: JPSCP has many conditions here, like removing wait timeout actions etc.
// if (thread->nt.status == THREADSTATUS_WAIT && newStatus != THREADSTATUS_WAITSUSPEND) {
__KernelChangeReadyState(thread, thread->GetUID(), (newStatus & THREADSTATUS_READY) != 0);
thread->nt.status = newStatus;
if (newStatus == THREADSTATUS_WAIT) {
@ -2258,8 +2355,10 @@ bool __CanExecuteCallbackNow(Thread *thread) {
return g_inCbCount == 0;
}
void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bool returnVoid, std::vector<int> args, bool reschedAfter)
void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, const u32 args[], int numargs, bool reschedAfter, SceUID cbId)
{
_dbg_assert_msg_(HLE, numargs <= 6, "MipsCalls can only take 6 args.");
if (thread) {
ActionAfterMipsCall *after = (ActionAfterMipsCall *) __KernelCreateAction(actionAfterMipsCall);
after->chainedAction = afterAction;
@ -2280,12 +2379,13 @@ void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bo
MipsCall *call = new MipsCall();
call->entryPoint = entryPoint;
for (size_t i = 0; i < args.size(); i++) {
for (int i = 0; i < numargs; i++) {
call->args[i] = args[i];
}
call->numArgs = (int) args.size();
call->numArgs = (int) numargs;
call->doAfter = afterAction;
call->tag = "callAddress";
call->cbId = cbId;
int callId = mipsCalls.add(call);
@ -2309,14 +2409,9 @@ void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bo
}
}
void __KernelDirectMipsCall(u32 entryPoint, Action *afterAction, bool returnVoid, u32 args[], int numargs, bool reschedAfter)
void __KernelDirectMipsCall(u32 entryPoint, Action *afterAction, u32 args[], int numargs, bool reschedAfter)
{
// TODO: get rid of the vector
std::vector<int> argsv;
for (int i = 0; i < numargs; i++)
argsv.push_back(args[i]);
__KernelCallAddress(__GetCurrentThread(), entryPoint, afterAction, returnVoid, argsv, reschedAfter);
__KernelCallAddress(__GetCurrentThread(), entryPoint, afterAction, args, numargs, reschedAfter, 0);
}
void __KernelExecuteMipsCallOnCurrentThread(int callId, bool reschedAfter)
@ -2341,7 +2436,6 @@ void __KernelExecuteMipsCallOnCurrentThread(int callId, bool reschedAfter)
call->savedV1 = currentMIPS->r[MIPS_REG_V1];
call->savedIdRegister = currentMIPS->r[MIPS_REG_CALL_ID];
call->savedId = cur->currentCallbackId;
call->returnVoid = false;
call->reschedAfter = reschedAfter;
// Set up the new state
@ -2355,7 +2449,8 @@ void __KernelExecuteMipsCallOnCurrentThread(int callId, bool reschedAfter)
currentMIPS->r[MIPS_REG_A0 + i] = call->args[i];
}
g_inCbCount++;
if (call->cbId != 0)
g_inCbCount++;
currentCallbackThreadID = currentThread;
}
@ -2392,7 +2487,8 @@ void __KernelReturnFromMipsCall()
currentMIPS->r[MIPS_REG_CALL_ID] = call->savedIdRegister;
cur->currentCallbackId = call->savedId;
g_inCbCount--;
if (call->cbId != 0)
g_inCbCount--;
currentCallbackThreadID = 0;
// yeah! back in the real world, let's keep going. Should we process more callbacks?
@ -2442,10 +2538,7 @@ void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread, bool reschedAfter)
// Alright, we're on the right thread
// Should save/restore wait state?
std::vector<int> args;
args.push_back(cb->nc.notifyCount);
args.push_back(cb->nc.notifyArg);
args.push_back(cb->nc.commonArgument);
const u32 args[] = {(u32) cb->nc.notifyCount, (u32) cb->nc.notifyArg, cb->nc.commonArgument};
// Clear the notify count / arg
cb->nc.notifyCount = 0;
@ -2457,7 +2550,7 @@ void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread, bool reschedAfter)
else
ERROR_LOG(HLE, "Something went wrong creating a restore action for a callback.");
__KernelCallAddress(thread, cb->nc.entrypoint, action, false, args, reschedAfter);
__KernelCallAddress(thread, cb->nc.entrypoint, action, args, 3, reschedAfter, cbId);
}
void ActionAfterCallback::run(MipsCall &call) {

View File

@ -26,6 +26,7 @@
void sceKernelChangeThreadPriority();
int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr);
int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr);
void sceKernelDelayThread();
void sceKernelDelayThreadCB();
@ -57,6 +58,7 @@ int sceKernelWaitThreadEndCB(SceUID threadID, u32 timeoutPtr);
void sceKernelGetThreadExitStatus();
u32 sceKernelGetThreadmanIdType(u32);
u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 idCountPtr);
u32 sceKernelExtendThreadStack(u32 cpu, u32 size, u32 entryAddr, u32 entryParameter);
struct SceKernelSysClock {
u32 lo;
@ -182,7 +184,7 @@ void sceKernelReferCallbackStatus();
class Action;
// Not an official Callback object, just calls a mips function on the current thread.
void __KernelDirectMipsCall(u32 entryPoint, Action *afterAction, bool returnVoid, u32 args[], int numargs, bool reschedAfter);
void __KernelDirectMipsCall(u32 entryPoint, Action *afterAction, u32 args[], int numargs, bool reschedAfter);
void __KernelReturnFromMipsCall(); // Called as HLE function
bool __KernelInCallback();
@ -207,6 +209,11 @@ int __KernelRegisterActionType(ActionCreator creator);
void __KernelRestoreActionType(int actionType, ActionCreator creator);
struct MipsCall {
MipsCall()
{
doAfter = NULL;
}
u32 entryPoint;
u32 cbId;
u32 args[6];
@ -217,7 +224,6 @@ struct MipsCall {
u32 savedPc;
u32 savedV0;
u32 savedV1;
bool returnVoid;
std::string tag;
u32 savedId;
bool reschedAfter;

View File

@ -58,69 +58,66 @@ struct SceKernelSysClock
u32 hi;
};
void sceKernelGetSystemTime()
int sceKernelGetSystemTime(u32 sysclockPtr)
{
SceKernelSysClock *clock = (SceKernelSysClock*)Memory::GetPointer(PARAM(0));
u64 t = CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz();
clock->lo = (u32)t;
clock->hi = t >> 32;
DEBUG_LOG(HLE,"sceKernelGetSystemTime(out:%08x%08x)",clock->hi, clock->lo);
RETURN(0);
Memory::Write_U64(t, sysclockPtr);
DEBUG_LOG(HLE, "sceKernelGetSystemTime(out:%16llx)", t);
return 0;
}
void sceKernelGetSystemTimeLow()
u32 sceKernelGetSystemTimeLow()
{
// This clock should tick at 1 Mhz.
u64 t = CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz();
// DEBUG_LOG(HLE,"%08x=sceKernelGetSystemTimeLow()",(u32)t);
RETURN((u32)t);
return (u32)t;
}
void sceKernelGetSystemTimeWide()
u64 sceKernelGetSystemTimeWide()
{
u64 t = CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz();
DEBUG_LOG(HLE,"%i=sceKernelGetSystemTimeWide()",(u32)t);
RETURN((u32)t);
currentMIPS->r[3] = t >> 32;
return t;
}
void sceKernelUSec2SysClock()
int sceKernelUSec2SysClock(u32 microsec, u32 clockPtr)
{
u32 microseconds = PARAM(0);
SceKernelSysClock *clock = (SceKernelSysClock*)Memory::GetPointer(PARAM(1));
u32 microseconds = microsec;
SceKernelSysClock *clock = (SceKernelSysClock*)Memory::GetPointer(clockPtr);
clock->lo = microseconds; //TODO: fix
DEBUG_LOG(HLE,"sceKernelUSec2SysClock(%i, %08x )",PARAM(0), PARAM(1));
RETURN(0);
DEBUG_LOG(HLE,"sceKernelUSec2SysClock(%i, %08x )",microsec,clockPtr);
return 0;
}
void sceKernelSysClock2USec()
{
SceKernelSysClock clock;
Memory::ReadStruct(PARAM(0), &clock);
DEBUG_LOG(HLE, "sceKernelSysClock2USec(clock = , lo = %08x, hi = %08x)", PARAM(1), PARAM(2));
u64 time = clock.lo | ((u64)clock.hi << 32);
if (Memory::IsValidAddress(PARAM(1)))
Memory::Write_U32((u32)(time / 1000000), PARAM(1));
if (Memory::IsValidAddress(PARAM(2)))
Memory::Write_U32((u32)(time % 1000000), PARAM(2));
RETURN(0);
}
void sceKernelSysClock2USecWide()
{
u64 clock = PARAM(0) | ((u64)PARAM(1) << 32);
DEBUG_LOG(HLE, "sceKernelSysClock2USecWide(clock = %llu, lo = %08x, hi = %08x)", clock, PARAM(2), PARAM(3));
if (Memory::IsValidAddress(PARAM(2)))
Memory::Write_U32((u32)(clock / 1000000), PARAM(2));
if (Memory::IsValidAddress(PARAM(3)))
Memory::Write_U32((u32)(clock % 1000000), PARAM(3));
RETURN(0);
}
u32 sceKernelUSec2SysClockWide(u32 usec)
u64 sceKernelUSec2SysClockWide(u32 usec)
{
DEBUG_LOG(HLE, "sceKernelUSec2SysClockWide(%i)", usec);
return usec * 1000000; // ?
return usec; // ?
}
int sceKernelSysClock2USec(u32 sysclockPtr, u32 highPtr, u32 lowPtr)
{
DEBUG_LOG(HLE, "sceKernelSysClock2USec(clock = %08x, lo = %08x, hi = %08x)", sysclockPtr, highPtr, lowPtr);
u64 time = Memory::Read_U64(sysclockPtr);
u32 highResult = (u32)(time / 1000000);
u32 lowResult = (u32)(time % 1000000);
if (Memory::IsValidAddress(highPtr))
Memory::Write_U32(highResult, highPtr);
if (Memory::IsValidAddress(lowPtr))
Memory::Write_U32(lowResult, lowPtr);
return 0;
}
int sceKernelSysClock2USecWide(u32 lowClock, u32 highClock, u32 lowPtr, u32 highPtr)
{
u64 clock = lowClock | ((u64)highClock << 32);
DEBUG_LOG(HLE, "sceKernelSysClock2USecWide(clock = %llu, lo = %08x, hi = %08x)", clock, lowPtr, highPtr);
if (Memory::IsValidAddress(lowPtr))
Memory::Write_U32((u32)(clock / 1000000), lowPtr);
if (Memory::IsValidAddress(highPtr))
Memory::Write_U32((u32)(clock % 1000000), highPtr);
return 0;
}
u32 sceKernelLibcClock()

View File

@ -19,13 +19,13 @@
u32 sceKernelLibcGettimeofday(u32 timeAddr);
u32 sceKernelLibcTime(u32 outPtr);
void sceKernelUSec2SysClock();
void sceKernelGetSystemTime();
void sceKernelGetSystemTimeLow();
void sceKernelGetSystemTimeWide();
void sceKernelSysClock2USec();
void sceKernelSysClock2USecWide();
u32 sceKernelUSec2SysClockWide(u32 usec);
int sceKernelUSec2SysClock(u32 microsec, u32 clockPtr);
int sceKernelGetSystemTime(u32 sysclockPtr);
u32 sceKernelGetSystemTimeLow();
u64 sceKernelGetSystemTimeWide();
int sceKernelSysClock2USec(u32 sysclockPtr, u32 highPtr, u32 lowPtr);
int sceKernelSysClock2USecWide(u32 lowClock, u32 highClock, u32 lowPtr, u32 highPtr);
u64 sceKernelUSec2SysClockWide(u32 usec);
u32 sceKernelLibcClock();
void __KernelTimeInit();

View File

@ -1055,7 +1055,7 @@ u32 sceMpegRingbufferPut(u32 ringbufferAddr, u32 numPackets, u32 available)
PostPutAction *action = (PostPutAction *) __KernelCreateAction(actionPostPut);
action->setRingAddr(ringbufferAddr);
u32 args[3] = {(u32)ringbuffer.data, numPackets, (u32)ringbuffer.callback_args};
__KernelDirectMipsCall(ringbuffer.callback_addr, action, false, args, 3, false);
__KernelDirectMipsCall(ringbuffer.callback_addr, action, args, 3, false);
} else {
ERROR_LOG(HLE, "sceMpegRingbufferPut: callback_addr zero");
}

View File

@ -439,6 +439,23 @@ u32 sceSasSetSteepWave(u32 sasCore, int voice, int unknown)
return 0;
}
u32 __sceSasSetVoiceATRAC3(u32 core, int voice, int atrac3Context)
{
ERROR_LOG(HLE,"UNIMPL __sceSasSetVoiceATRAC3(%08x, %i, %i)", core, voice, atrac3Context);
return 0;
}
u32 __sceSasConcatenateATRAC3(u32 core, int voice, u32 atrac3DataAddr, int atrac3DataLength)
{
ERROR_LOG(HLE,"UNIMPL __sceSasConcatenateATRAC3(%08x, %i, %i)", core, voice, atrac3DataAddr, atrac3DataLength);
return 0;
}
u32 __sceSasUnsetATRAC3(u32 core, int voice)
{
ERROR_LOG(HLE,"UNIMPL __sceSasUnsetATRAC3(%08x, %i, %i)", core, voice);
return 0;
}
const HLEFunction sceSasCore[] =
{
{0x42778a9f, WrapU_UUUUU<sceSasInit>, "__sceSasInit"},
@ -470,6 +487,9 @@ const HLEFunction sceSasCore[] =
{0xe855bf76, WrapU_UU<sceSasSetOutputMode>, "__sceSasSetOutputmode"},
{0x07f58c24, WrapU_UU<sceSasGetAllEnvelopeHeights>, "__sceSasGetAllEnvelopeHeights"},
{0xE1CD9561, WrapU_UIUII<sceSasSetVoicePCM>, "__sceSasSetVoicePCM"},
{0x4AA9EAD6, WrapU_UII<__sceSasSetVoiceATRAC3>,"__sceSasSetVoiceATRAC3"},
{0x7497EA85, WrapU_UIUI<__sceSasConcatenateATRAC3>,"__sceSasConcatenateATRAC3"},
{0xF6107F00, WrapU_UI<__sceSasUnsetATRAC3>,"__sceSasUnsetATRAC3"},
};
void Register_sceSasCore()

View File

@ -113,7 +113,11 @@ void Jit::GenerateFixedCode()
// * downcount
// * R2-R4
// Really starting to run low on registers already though...
#ifdef UNUSABLE_MMAP
MOVI2R(R11, (u32)Memory::m_pRAM - 0x08000000);
#else
MOVI2R(R11, (u32)Memory::base);
#endif
MOVI2R(R10, (u32)mips_);
MOVI2R(R9, (u32)GetBlockCache()->GetCodePointers());

View File

@ -1418,6 +1418,7 @@ namespace MIPSInt
VectorSize sz = GetVecSize(op);
float c = constants[conNum];
float temp[4] = {c,c,c,c};
ApplyPrefixD(temp, sz);
WriteVector(temp, sz, vd);
PC += 4;
EatPrefixes();
@ -1739,4 +1740,25 @@ bad:
EatPrefixes();
}
void Int_Vlgb(u32 op)
{
// S & D valid
_dbg_assert_msg_(CPU,0,"vlgb not implemented");
}
void Int_Vwbn(u32 op)
{
// S & D valid
_dbg_assert_msg_(CPU,0,"vwbn not implemented");
}
void Int_Vsbn(u32 op)
{
_dbg_assert_msg_(CPU,0,"vsbn not implemented");
}
void Int_Vsbz(u32 op)
{
_dbg_assert_msg_(CPU,0,"vsbz not implemented");
}
}

View File

@ -77,5 +77,8 @@ namespace MIPSInt
void Int_Vslt(u32 op);
void Int_Vmfvc(u32 op);
void Int_Vmtvc(u32 op);
}
void Int_Vlgb(u32 op);
void Int_Vwbn(u32 op);
void Int_Vsbn(u32 op);
void Int_Vsbz(u32 op);
}

View File

@ -415,8 +415,7 @@ const MIPSInstruction tableCop0[32] =
{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},
};
//we won't encounter these since we only do user mode emulation
// we won't encounter these since we only do user mode emulation
const MIPSInstruction tableCop0CO[64] =
{
{-2},
@ -481,7 +480,7 @@ const MIPSInstruction tableVFPU0[8] =
{
INSTR("vadd",&Jit::Comp_Generic, Dis_VectorSet3, Int_VecDo3, IS_VFPU),
INSTR("vsub",&Jit::Comp_Generic, Dis_VectorSet3, Int_VecDo3, IS_VFPU),
INSTR("vsbn",&Jit::Comp_Generic, Dis_VectorSet3, 0, IS_VFPU),
INSTR("vsbn",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vsbn, IS_VFPU),
{-2}, {-2}, {-2}, {-2},
INSTR("vdiv",&Jit::Comp_Generic, Dis_VectorSet3, Int_VecDo3, IS_VFPU),
@ -535,14 +534,14 @@ const MIPSInstruction tableVFPU4Jump[32] = //110100 xxxxx
{-2},
{-2},
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, Int_Vwbn, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, Int_Vwbn, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, Int_Vwbn, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, Int_Vwbn, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, Int_Vwbn, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, Int_Vwbn, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, Int_Vwbn, IS_VFPU),
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, Int_Vwbn, IS_VFPU),
};
const MIPSInstruction tableVFPU7[32] =
@ -555,7 +554,8 @@ const MIPSInstruction tableVFPU7[32] =
{-2},{-2},{-2},{-2},
//8
{-2},{-2},{-2},{-2},
{-2},{-2},{-2},{-2},
INSTR("vsbz", &Jit::Comp_Generic, Dis_Generic, Int_Vsbz, IS_VFPU),
{-2},{-2},{-2},
//16
{-2},
{-2},
@ -565,7 +565,7 @@ const MIPSInstruction tableVFPU7[32] =
{-2},
{-2},
{-2},
INSTR("vlgb", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
INSTR("vlgb", &Jit::Comp_Generic, Dis_Generic, Int_Vlgb, IS_VFPU),
//24
INSTR("vuc2i", &Jit::Comp_Generic, Dis_Vs2i, Int_Vx2i, IS_VFPU), // Seen in BraveStory, initialization 110100 00001110000 000 0001 0000 0000
INSTR("vc2i", &Jit::Comp_Generic, Dis_Vs2i, Int_Vx2i, IS_VFPU),

View File

@ -297,17 +297,16 @@ namespace MIPSComp
// "over-shifts" work the same as on x86 - only bottom 5 bits are used to get the shift value
void Jit::CompShiftVar(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg))
{
DISABLE;
int rd = _RD;
int rt = _RT;
int rs = _RS;
gpr.FlushLockX(ECX);
gpr.Lock(rd, rt, rs);
gpr.BindToRegister(rd, true, true);
if (rd != rt)
MOV(32, gpr.R(rd), gpr.R(rt));
gpr.BindToRegister(rd, rd == rt || rd == rs, true);
MOV(32, R(ECX), gpr.R(rs)); // Only ECX can be used for variable shifts.
AND(32, R(ECX), Imm32(0x1f));
if (rd != rt)
MOV(32, gpr.R(rd), gpr.R(rt));
(this->*shift)(32, gpr.R(rd), R(ECX));
gpr.UnlockAll();
gpr.UnlockAllX();

View File

@ -136,7 +136,7 @@ void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely)
int rs = _RS;
u32 targetAddr = js.compilerPC + offset + 4;
u32 delaySlotOp = Memory::ReadUnchecked_U32(js.compilerPC+4);
u32 delaySlotOp = Memory::Read_Instruction(js.compilerPC+4);
bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rt, rs);
CONDITIONAL_NICE_DELAYSLOT;
if (!likely && delaySlotIsNice)
@ -191,7 +191,7 @@ void Jit::BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool andLink, bool likely)
int rs = _RS;
u32 targetAddr = js.compilerPC + offset + 4;
u32 delaySlotOp = Memory::ReadUnchecked_U32(js.compilerPC + 4);
u32 delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4);
bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rs);
CONDITIONAL_NICE_DELAYSLOT;
if (!likely && delaySlotIsNice)
@ -285,7 +285,7 @@ void Jit::BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely)
int offset = (signed short)(op & 0xFFFF) << 2;
u32 targetAddr = js.compilerPC + offset + 4;
u32 delaySlotOp = Memory::ReadUnchecked_U32(js.compilerPC + 4);
u32 delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4);
bool delaySlotIsNice = IsDelaySlotNiceFPU(op, delaySlotOp);
CONDITIONAL_NICE_DELAYSLOT;
if (!likely && delaySlotIsNice)
@ -346,7 +346,7 @@ void Jit::BranchVFPUFlag(u32 op, Gen::CCFlags cc, bool likely)
int offset = (signed short)(op & 0xFFFF) << 2;
u32 targetAddr = js.compilerPC + offset + 4;
u32 delaySlotOp = Memory::ReadUnchecked_U32(js.compilerPC + 4);
u32 delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4);
bool delaySlotIsNice = IsDelaySlotNiceVFPU(op, delaySlotOp);
CONDITIONAL_NICE_DELAYSLOT;
if (!likely && delaySlotIsNice)
@ -443,7 +443,7 @@ void Jit::Comp_JumpReg(u32 op)
}
int rs = _RS;
u32 delaySlotOp = Memory::ReadUnchecked_U32(js.compilerPC + 4);
u32 delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4);
bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rs);
CONDITIONAL_NICE_DELAYSLOT;

View File

@ -148,44 +148,70 @@ namespace MIPSComp
CompITypeMemWrite(op, 32, (void *) &Memory::Write_U32);
break;
case 134: //lwl
case 34: //lwl
{
Crash();
//u32 shift = (addr & 3) << 3;
//u32 mem = ReadMem32(addr & 0xfffffffc);
//R(rt) = ( u32(R(rt)) & (0x00ffffff >> shift) ) | ( mem << (24 - shift) );
u32 nextOp = Memory::Read_Instruction(js.compilerPC + 4);
// Looking for lwr rd, offset-3(rs) which makes a pair.
u32 desiredOp = ((op + (4 << 26)) & 0xFFFF0000) + (offset - 3);
if (!js.inDelaySlot && nextOp == desiredOp)
{
EatInstruction(nextOp);
// nextOp has the correct address.
CompITypeMemRead(nextOp, 32, &XEmitter::MOVZX, (void *) &Memory::Read_U32);
}
else
Comp_Generic(op);
}
break;
case 138: //lwr
case 38: //lwr
{
Crash();
//u32 shift = (addr & 3) << 3;
//u32 mem = ReadMem32(addr & 0xfffffffc);
//R(rt) = ( u32(rt) & (0xffffff00 << (24 - shift)) ) | ( mem >> shift );
u32 nextOp = Memory::Read_Instruction(js.compilerPC + 4);
// Looking for lwl rd, offset+3(rs) which makes a pair.
u32 desiredOp = ((op - (4 << 26)) & 0xFFFF0000) + (offset + 3);
if (!js.inDelaySlot && nextOp == desiredOp)
{
EatInstruction(nextOp);
// op has the correct address.
CompITypeMemRead(op, 32, &XEmitter::MOVZX, (void *) &Memory::Read_U32);
}
else
Comp_Generic(op);
}
break;
case 142: //swl
case 42: //swl
{
Crash();
//u32 shift = (addr & 3) << 3;
//u32 mem = ReadMem32(addr & 0xfffffffc);
//WriteMem32((addr & 0xfffffffc), ( ( u32(R(rt)) >> (24 - shift) ) ) |
// ( mem & (0xffffff00 << shift) ));
u32 nextOp = Memory::Read_Instruction(js.compilerPC + 4);
// Looking for swr rd, offset-3(rs) which makes a pair.
u32 desiredOp = ((op + (4 << 26)) & 0xFFFF0000) + (offset - 3);
if (!js.inDelaySlot && nextOp == desiredOp)
{
EatInstruction(nextOp);
// nextOp has the correct address.
CompITypeMemWrite(nextOp, 32, (void *) &Memory::Write_U32);
}
else
Comp_Generic(op);
}
break;
case 146: //swr
case 46: //swr
{
Crash();
// u32 shift = (addr & 3) << 3;
// u32 mem = ReadMem32(addr & 0xfffffffc);
//
// WriteMem32((addr & 0xfffffffc), ( ( u32(R(rt)) << shift ) |
// (mem & (0x00ffffff >> (24 - shift)) ) ) );
u32 nextOp = Memory::Read_Instruction(js.compilerPC + 4);
// Looking for swl rd, offset+3(rs) which makes a pair.
u32 desiredOp = ((op - (4 << 26)) & 0xFFFF0000) + (offset + 3);
if (!js.inDelaySlot && nextOp == desiredOp)
{
EatInstruction(nextOp);
// op has the correct address.
CompITypeMemWrite(op, 32, (void *) &Memory::Write_U32);
}
else
Comp_Generic(op);
}
break;
default:
Comp_Generic(op);
return ;

View File

@ -158,6 +158,18 @@ void Jit::CompileAt(u32 addr)
MIPSCompileOp(op);
}
void Jit::EatInstruction(u32 op)
{
u32 info = MIPSGetInfo(op);
_dbg_assert_msg_(JIT, !(info & DELAYSLOT), "Never eat a branch op.");
_dbg_assert_msg_(JIT, !js.inDelaySlot, "Never eat an instruction inside a delayslot.");
CheckJitBreakpoint(js.compilerPC + 4, 0);
js.numInstructions++;
js.compilerPC += 4;
js.downcountAmount += MIPSGetInstructionCycleEstimate(op);
}
void Jit::Compile(u32 em_address)
{
if (GetSpaceLeft() < 0x10000 || blocks.IsFull())
@ -203,7 +215,7 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b)
gpr.Start(mips_, analysis);
fpr.Start(mips_, analysis);
int numInstructions = 0;
js.numInstructions = 0;
while (js.compiling)
{
// Jit breakpoints are quite fast, so let's do them in release too.
@ -215,13 +227,13 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b)
MIPSCompileOp(inst);
js.compilerPC += 4;
numInstructions++;
js.numInstructions++;
}
b->codeSize = (u32)(GetCodePtr() - b->normalEntry);
NOP();
AlignCode4();
b->originalSize = numInstructions;
b->originalSize = js.numInstructions;
return b->normalEntry;
}

View File

@ -53,6 +53,7 @@ struct JitState
bool cancel;
bool inDelaySlot;
int downcountAmount;
int numInstructions;
bool compiling; // TODO: get rid of this in favor of using analysis results to determine end of block
JitBlock *curBlock;
@ -107,8 +108,6 @@ public:
void Compile(u32 em_address); // Compiles a block at current MIPS PC
const u8 *DoJit(u32 em_address, JitBlock *b);
// See CompileDelaySlotFlags for flags.
void CompileDelaySlot(int flags);
void CompileAt(u32 addr);
void Comp_RunBlock(u32 op);
@ -151,6 +150,10 @@ private:
void FlushAll();
void WriteDowncount(int offset = 0);
// See CompileDelaySlotFlags for flags.
void CompileDelaySlot(int flags);
void EatInstruction(u32 op);
void WriteExit(u32 destination, int exit_num);
void WriteExitDestInEAX();
// void WriteRfiExitDestInEAX();

View File

@ -54,6 +54,7 @@ static const int flushOnChangedBeforeCommandList[] = {
GE_CMD_ALPHATESTENABLE,
GE_CMD_ALPHATEST,
GE_CMD_COLORTESTENABLE,
GE_CMD_COLORTEST,
GE_CMD_COLORTESTMASK,
GE_CMD_COLORREF,
GE_CMD_MINZ,GE_CMD_MAXZ,
@ -318,12 +319,12 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
case GE_CMD_BASE:
break;
case GE_CMD_VADDR: /// <<8????
gstate_c.vertexAddr = ((gstate.base & 0x00FF0000) << 8)|data;
case GE_CMD_VADDR:
gstate_c.vertexAddr = gstate_c.getRelativeAddress(data);
break;
case GE_CMD_IADDR:
gstate_c.indexAddr = ((gstate.base & 0x00FF0000) << 8)|data;
gstate_c.indexAddr = gstate_c.getRelativeAddress(data);
break;
case GE_CMD_PRIM:
@ -387,7 +388,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
case GE_CMD_JUMP:
{
u32 target = gstate_c.getJumpAddress(data);
u32 target = gstate_c.getRelativeAddress(data);
if (Memory::IsValidAddress(target)) {
currentList->pc = target - 4; // pc will be increased after we return, counteract that
} else {
@ -400,7 +401,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
{
// Saint Seiya needs correct support for relative calls.
u32 retval = currentList->pc + 4;
u32 target = gstate_c.getJumpAddress(data);
u32 target = gstate_c.getRelativeAddress(data);
if (stackptr == ARRAY_SIZE(stack)) {
ERROR_LOG(G3D, "CALL: Stack full!");
} else if (!Memory::IsValidAddress(target)) {

View File

@ -347,12 +347,27 @@ static void SwapUVs(TransformedVertex &a, TransformedVertex &b) {
// to to or
// 1 0 0 1 1 2 3 0
// Used by Star Soldier and Ys vs Sora.
static void RotateUVs(TransformedVertex v[4]) {
if (/* (v[0].x > v[2].x && v[0].y < v[2].y) || */ // This first check seems wrong..
(v[0].x < v[2].x && v[0].y > v[2].y)) {
// See comment below where this was called before.
/*
static void RotateUV(TransformedVertex v[4]) {
float x1 = v[2].x;
float x2 = v[0].x;
float y1 = v[2].y;
float y2 = v[0].y;
if ((x1 < x2 && y1 < y2) || (x1 > x2 && y1 > y2))
SwapUVs(v[1], v[3]);
}*/
static void RotateUVThrough(TransformedVertex v[4]) {
float x1 = v[2].x;
float x2 = v[0].x;
float y1 = v[2].y;
float y2 = v[0].y;
if ((x1 < x2 && y1 > y2) || (x1 > x2 && y1 < y2))
SwapUVs(v[1], v[3]);
}
}
// This is the software transform pipeline, which is necessary for supporting RECT
@ -620,7 +635,13 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
trans[3].u = saved.u;
// That's the four corners. Now process UV rotation.
RotateUVs(trans);
if (throughmode)
RotateUVThrough(trans);
// Apparently, non-through RotateUV just breaks things.
// If we find a game where it helps, we'll just have to figure out how they differ.
// Possibly, it has something to do with flipped viewport Y axis, which a few games use.
// else
// RotateUV(trans);
// bottom right
trans[4] = trans[0];

View File

@ -65,6 +65,10 @@ bool GPUCommon::InterpretList(DisplayList &list)
prev = 0;
finished = false;
// I don't know if this is the correct place to zero this, but something
// need to do it. See Sol Trigger title screen.
gstate_c.offsetAddr = 0;
if (!Memory::IsValidAddress(list.pc)) {
ERROR_LOG(G3D, "DL PC = %08x WTF!!!!", list.pc);
return true;

View File

@ -252,7 +252,7 @@ struct GPUStateCache
float vpHeight;
u32 getJumpAddress(u32 data) const;
u32 getRelativeAddress(u32 data) const;
};
// TODO: Implement support for these.
@ -329,7 +329,7 @@ extern GPUStateCache gstate_c;
extern GPUInterface *gpu;
extern GPUStatistics gpuStats;
inline u32 GPUStateCache::getJumpAddress(u32 data) const {
inline u32 GPUStateCache::getRelativeAddress(u32 data) const {
u32 baseExtended = ((gstate.base & 0x0F0000) << 8) | (data & 0xFFFFFF);
return (gstate_c.offsetAddr + baseExtended) & 0x0FFFFFFF;
}

View File

@ -85,7 +85,7 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer) {
case GE_CMD_CALL:
{
u32 retval = pc + 4;
u32 target = gstate_c.getJumpAddress(op & 0xFFFFFF);
u32 target = gstate_c.getRelativeAddress(op & 0xFFFFFF);
sprintf(buffer, "CMD CALL - %08x to %08x, ret=%08x", pc, target, retval);
}
break;
@ -729,6 +729,18 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer) {
sprintf(buffer, "ZMask: %06x", data);
break;
case GE_CMD_COLORTEST:
sprintf(buffer, "ColorTest: %06", data);
break;
case GE_CMD_COLORREF:
sprintf(buffer, "ColorRef: %06", data);
break;
case GE_CMD_COLORTESTMASK:
sprintf(buffer, "ColorTestMask: %06", data);
break;
case GE_CMD_MASKRGB:
sprintf(buffer, "MaskRGB: %06x", data);
break;

View File

@ -109,27 +109,12 @@ void EmuThread::run()
UpdateInputState(input_state);
static const int mapping[12][2] = {
{PAD_BUTTON_A, CTRL_CROSS},
{PAD_BUTTON_B, CTRL_CIRCLE},
{PAD_BUTTON_X, CTRL_SQUARE},
{PAD_BUTTON_Y, CTRL_TRIANGLE},
{PAD_BUTTON_UP, CTRL_UP},
{PAD_BUTTON_DOWN, CTRL_DOWN},
{PAD_BUTTON_LEFT, CTRL_LEFT},
{PAD_BUTTON_RIGHT, CTRL_RIGHT},
{PAD_BUTTON_LBUMPER, CTRL_LTRIGGER},
{PAD_BUTTON_RBUMPER, CTRL_RTRIGGER},
{PAD_BUTTON_START, CTRL_START},
{PAD_BUTTON_SELECT, CTRL_SELECT},
};
for (int i = 0; i < 12; i++) {
if (input_state->pad_buttons_down & mapping[i][0]) {
__CtrlButtonDown(mapping[i][1]);
for (int i = 0; i < controllistCount; i++) {
if (input_state->pad_buttons_down & controllist[i].emu_id) {
__CtrlButtonDown(controllist[i].psp_id);
}
if (input_state->pad_buttons_up & mapping[i][0]) {
__CtrlButtonUp(mapping[i][1]);
if (input_state->pad_buttons_up & controllist[i].emu_id) {
__CtrlButtonUp(controllist[i].psp_id);
}
}
__CtrlSetAnalog(input_state->pad_lstick_x, input_state->pad_lstick_y);

View File

@ -1,75 +1,81 @@
TARGET = PPSSPPQt
QT += core gui opengl
include(Settings.pri)
linux {
CONFIG += mobility
MOBILITY += multimedia
}
else {
QT += multimedia
}
# Libs
symbian: LIBS += -lCore.lib -lCommon.lib -lNative.lib -lcone -leikcore -lavkon -lezlib
blackberry: LIBS += -L. -lCore -lCommon -lNative -lscreen -lsocket -lstdc++
win32: LIBS += -L. -lCore -lCommon -lNative -lwinmm -lws2_32 -lkernel32 -luser32 -lgdi32 -lshell32 -lcomctl32 -ldsound -lxinput
linux: LIBS += -L. -lCore -lCommon -lNative
# Main
SOURCES += ../native/base/QtMain.cpp
HEADERS += ../native/base/QtMain.h
# Native
SOURCES += ../android/jni/EmuScreen.cpp \
../android/jni/MenuScreens.cpp \
../android/jni/GamepadEmu.cpp \
../android/jni/UIShader.cpp \
../android/jni/ui_atlas.cpp
INCLUDEPATH += .. ../Common ../native
# Temporarily only use new UI for Linux desktop
linux:!mobile_platform {
SOURCES += mainwindow.cpp \
debugger_disasm.cpp \
EmuThread.cpp\
QtHost.cpp \
qtemugl.cpp \
ctrldisasmview.cpp \
ctrlregisterlist.cpp \
controls.cpp
HEADERS += mainwindow.h \
debugger_disasm.h \
EmuThread.h \
QtHost.h \
qtemugl.h \
ctrldisasmview.h \
ctrlregisterlist.h \
controls.h
} else {
SOURCES += ../android/jni/NativeApp.cpp
}
# Packaging
symbian {
vendorinfo = "%{\"Qtness\"}" ":\"Qtness\""
packageheader = "$${LITERAL_HASH}{\"PPSSPP\"}, (0xE0095B1D), 0, 6, 1, TYPE=SA"
deployinfo.pkg_prerules = packageheader vendorinfo
assets.sources = ../android/assets/ui_atlas.zim ../assets/ppge_atlas.zim
assets.path = E:/PPSSPP
DEPLOYMENT += deployinfo assets
ICON = ../assets/icon.svg
# 268MB maximum
TARGET.EPOCHEAPSIZE = 0x40000 0x10000000
TARGET.EPOCSTACKSIZE = 0x10000
}
linux:!mobile_platform {
FORMS += mainwindow.ui \
debugger_disasm.ui \
controls.ui
}
TARGET = PPSSPPQt
QT += core gui opengl
include(Settings.pri)
linux {
CONFIG += mobility
MOBILITY += multimedia
}
else {
QT += multimedia
}
# Libs
symbian: LIBS += -lCore.lib -lCommon.lib -lNative.lib -lcone -leikcore -lavkon -lezlib
blackberry: LIBS += -L. -lCore -lCommon -lNative -lscreen -lsocket -lstdc++
win32: LIBS += -L. -lCore -lCommon -lNative -lwinmm -lws2_32 -lkernel32 -luser32 -lgdi32 -lshell32 -lcomctl32 -ldsound -lxinput
linux: LIBS += -L. -lCore -lCommon -lNative
linux: PRE_TARGETDEPS += ./libCommon.a ./libCore.a ./libNative.a
# Main
SOURCES += ../native/base/QtMain.cpp \
qkeyedit.cpp
HEADERS += ../native/base/QtMain.h \
qkeyedit.h
# Native
SOURCES += ../android/jni/EmuScreen.cpp \
../android/jni/MenuScreens.cpp \
../android/jni/GamepadEmu.cpp \
../android/jni/UIShader.cpp \
../android/jni/ui_atlas.cpp
INCLUDEPATH += .. ../Common ../native
# Temporarily only use new UI for Linux desktop
linux:!mobile_platform {
SOURCES += mainwindow.cpp \
debugger_disasm.cpp \
EmuThread.cpp\
QtHost.cpp \
qtemugl.cpp \
ctrldisasmview.cpp \
ctrlregisterlist.cpp \
controls.cpp
HEADERS += mainwindow.h \
debugger_disasm.h \
EmuThread.h \
QtHost.h \
qtemugl.h \
ctrldisasmview.h \
ctrlregisterlist.h \
controls.h
} else {
SOURCES += ../android/jni/NativeApp.cpp
}
# Packaging
symbian {
vendorinfo = "%{\"Qtness\"}" ":\"Qtness\""
packageheader = "$${LITERAL_HASH}{\"PPSSPP\"}, (0xE0095B1D), 0, 6, 1, TYPE=SA"
deployinfo.pkg_prerules = packageheader vendorinfo
assets.sources = ../android/assets/ui_atlas.zim ../assets/ppge_atlas.zim
assets.path = E:/PPSSPP
DEPLOYMENT += deployinfo assets
ICON = ../assets/icon.svg
# 268MB maximum
TARGET.EPOCHEAPSIZE = 0x40000 0x10000000
TARGET.EPOCSTACKSIZE = 0x10000
}
linux:!mobile_platform {
FORMS += mainwindow.ui \
debugger_disasm.ui \
controls.ui
RESOURCES += \
resources.qrc
}

View File

@ -1,3 +1,4 @@
TEMPLATE = subdirs
SUBDIRS = Native.pro Core.pro Common.pro PPSSPP.pro
CONFIG += ordered
PPSSPP.depends = Native.pro Core.pro Common.pro

View File

@ -1,29 +1,24 @@
#include "controls.h"
#include "ui_controls.h"
#include "Core/Config.h"
struct Controls_
{
char* command;
char* key;
};
const Controls_ controllist[] = {
{"Start","1"},
{"Select","2"},
{"Square","Z"},
{"Triangle","A"},
{"Circle","S"},
{"Cross","X"},
{"Left Trigger","Q"},
{"Right Trigger","W"},
{"Up","Arrow Up"},
{"Down","Arrow Down"},
{"Left","Arrow Left"},
{"Right","Arrow Right"},
{"Analog Up","I"},
{"Analog Down","K"},
{"Analog Left","J"},
{"Analog Right","L"},
Controls_ controllist[] = {
{"Edit_Start", "Start", Qt::Key_1, PAD_BUTTON_START, CTRL_START},
{"Edit_Select", "Select", Qt::Key_2, PAD_BUTTON_SELECT, CTRL_SELECT},
{"Edit_S", "Square", Qt::Key_Z, PAD_BUTTON_X, CTRL_SQUARE},
{"Edit_T", "Triangle", Qt::Key_A, PAD_BUTTON_Y, CTRL_TRIANGLE},
{"Edit_O", "Circle", Qt::Key_S, PAD_BUTTON_B, CTRL_CIRCLE},
{"Edit_X", "Cross", Qt::Key_X, PAD_BUTTON_A, CTRL_CROSS},
{"Edit_LT", "Left Trigger", Qt::Key_Q, PAD_BUTTON_LBUMPER, CTRL_LTRIGGER},
{"Edit_RT", "Right Trigger", Qt::Key_W, PAD_BUTTON_RBUMPER, CTRL_RTRIGGER},
{"Edit_Up", "Up", Qt::Key_Up, PAD_BUTTON_UP, CTRL_UP},
{"Edit_Down", "Down", Qt::Key_Down, PAD_BUTTON_DOWN, CTRL_DOWN},
{"Edit_Left", "Left", Qt::Key_Left, PAD_BUTTON_LEFT, CTRL_LEFT},
{"Edit_Right", "Right", Qt::Key_Right, PAD_BUTTON_RIGHT, CTRL_RIGHT},
{"", "Analog Up", Qt::Key_I, PAD_BUTTON_JOY_UP, 0},
{"", "Analog Down", Qt::Key_K, PAD_BUTTON_JOY_DOWN,0},
{"", "Analog Left", Qt::Key_J, PAD_BUTTON_JOY_LEFT,0},
{"", "Analog Right", Qt::Key_L, PAD_BUTTON_JOY_RIGHT,0},
};
Controls::Controls(QWidget *parent) :
@ -32,20 +27,12 @@ Controls::Controls(QWidget *parent) :
{
ui->setupUi(this);
int numRows = sizeof(controllist)/sizeof(Controls_);
ui->listControls->setRowCount(numRows);
for(int i = 0; i < numRows; i++)
for(int i = 0; i < controllistCount; i++)
{
QTableWidgetItem* item = new QTableWidgetItem();
item->setText(controllist[i].command);
ui->listControls->setItem(i,0,item);
item = new QTableWidgetItem();
item->setText(controllist[i].key);
ui->listControls->setItem(i,1,item);
ui->listControls->setRowHeight(i,15);
if(g_Config.iMappingMap.find(i) != g_Config.iMappingMap.end())
{
controllist[i].key = (Qt::Key)g_Config.iMappingMap[i];
}
}
}
@ -53,3 +40,41 @@ Controls::~Controls()
{
delete ui;
}
void Controls::showEvent(QShowEvent*)
{
for(int i = 0; i < controllistCount; i++)
{
if(g_Config.iMappingMap.find(i) != g_Config.iMappingMap.end())
{
controllist[i].key = (Qt::Key)g_Config.iMappingMap[i];
}
if(controllist[i].editName != "")
{
QLineEdit* edit = findChild<QLineEdit*>(controllist[i].editName);
if(edit)
{
QKeySequence sec(controllist[i].key);
edit->setText(sec.toString());
}
}
}
}
void Controls::on_buttonBox_accepted()
{
for(int i = 0; i < controllistCount; i++)
{
if(controllist[i].editName != "")
{
QLineEdit* edit = findChild<QLineEdit*>(controllist[i].editName);
if(edit)
{
QKeySequence sec(edit->text());
controllist[i].key = (Qt::Key)sec[0];
g_Config.iMappingMap[i] = sec[0];
}
}
}
}

View File

@ -2,11 +2,26 @@
#define CONTROLS_H
#include <QDialog>
#include "native/input/input_state.h"
#include "Core/HLE/sceCtrl.h"
namespace Ui {
class Controls;
}
struct Controls_
{
public:
QString editName;
QString command;
Qt::Key key;
int emu_id;
int psp_id;
};
const int controllistCount = 16;
extern Controls_ controllist[];
class Controls : public QDialog
{
Q_OBJECT
@ -14,7 +29,11 @@ class Controls : public QDialog
public:
explicit Controls(QWidget *parent = 0);
~Controls();
void showEvent(QShowEvent *);
private slots:
void on_buttonBox_accepted();
private:
Ui::Controls *ui;
};

View File

@ -6,43 +6,211 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<width>618</width>
<height>351</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Dialog</string>
<string>Controls</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Note : Currently controls are NOT configurable.</string>
<widget class="QWidget" name="widget" native="true">
<property name="minimumSize">
<size>
<width>600</width>
<height>300</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QTableWidget" name="listControls">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
<property name="maximumSize">
<size>
<width>600</width>
<height>300</height>
</size>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="columnCount">
<number>2</number>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<column/>
<column/>
<widget class="QLabel" name="PSP_Img">
<property name="geometry">
<rect>
<x>50</x>
<y>50</y>
<width>501</width>
<height>191</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp.png</pixmap>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_Up">
<property name="geometry">
<rect>
<x>50</x>
<y>100</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_Left">
<property name="geometry">
<rect>
<x>30</x>
<y>130</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_Right">
<property name="geometry">
<rect>
<x>80</x>
<y>130</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_Down">
<property name="geometry">
<rect>
<x>50</x>
<y>160</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_Home">
<property name="geometry">
<rect>
<x>150</x>
<y>240</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_Start">
<property name="geometry">
<rect>
<x>410</x>
<y>240</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_Select">
<property name="geometry">
<rect>
<x>360</x>
<y>240</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_X">
<property name="geometry">
<rect>
<x>510</x>
<y>160</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_S">
<property name="geometry">
<rect>
<x>480</x>
<y>130</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_O">
<property name="geometry">
<rect>
<x>530</x>
<y>130</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_T">
<property name="geometry">
<rect>
<x>510</x>
<y>100</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_RT">
<property name="geometry">
<rect>
<x>440</x>
<y>20</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QKeyEdit" name="Edit_LT">
<property name="geometry">
<rect>
<x>120</x>
<y>20</y>
<width>41</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="PSP_Img_2">
<property name="geometry">
<rect>
<x>50</x>
<y>50</y>
<width>501</width>
<height>191</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/images/resources/psp_map.png</pixmap>
</property>
</widget>
<zorder>PSP_Img</zorder>
<zorder>PSP_Img_2</zorder>
<zorder>Edit_Up</zorder>
<zorder>Edit_Left</zorder>
<zorder>Edit_Right</zorder>
<zorder>Edit_Down</zorder>
<zorder>Edit_Home</zorder>
<zorder>Edit_Start</zorder>
<zorder>Edit_Select</zorder>
<zorder>Edit_X</zorder>
<zorder>Edit_S</zorder>
<zorder>Edit_O</zorder>
<zorder>Edit_T</zorder>
<zorder>Edit_RT</zorder>
<zorder>Edit_LT</zorder>
</widget>
</item>
<item>
@ -57,7 +225,16 @@
</item>
</layout>
</widget>
<resources/>
<customwidgets>
<customwidget>
<class>QKeyEdit</class>
<extends>QLineEdit</extends>
<header>qkeyedit.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="resources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>

View File

@ -20,28 +20,6 @@
#include "QtHost.h"
#include "EmuThread.h"
// Input
const int buttonMappings[18] = {
Qt::Key_X, //A
Qt::Key_S, //B
Qt::Key_Z, //X
Qt::Key_A, //Y
Qt::Key_W, //LBUMPER
Qt::Key_Q, //RBUMPER
Qt::Key_1, //START
Qt::Key_2, //SELECT
Qt::Key_Up, //UP
Qt::Key_Down, //DOWN
Qt::Key_Left, //LEFT
Qt::Key_Right, //RIGHT
0, //MENU (event)
Qt::Key_Backspace, //BACK
Qt::Key_I, //JOY UP
Qt::Key_K, //JOY DOWN
Qt::Key_J, //JOY LEFT
Qt::Key_L, //JOY RIGHT
};
const char *stateToLoad = NULL;
MainWindow::MainWindow(QWidget *parent) :
@ -673,20 +651,20 @@ void MainWindow::keyPressEvent(QKeyEvent *e)
return;
}
for (int b = 0; b < 14; b++) {
if (e->key() == buttonMappings[b])
for (int b = 0; b < controllistCount; b++) {
if (e->key() == controllist[b].key)
{
input_state.pad_buttons |= (1<<b);
input_state.pad_buttons |= (controllist[b].emu_id);
}
}
}
void MainWindow::keyReleaseEvent(QKeyEvent *e)
{
for (int b = 0; b < 14; b++) {
if (e->key() == buttonMappings[b])
for (int b = 0; b < controllistCount; b++) {
if (e->key() == controllist[b].key)
{
input_state.pad_buttons &= ~(1<<b);
input_state.pad_buttons &= ~(controllist[b].emu_id);
}
}
}

21
Qt/qkeyedit.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "qkeyedit.h"
#include <QKeySequence>
#include <QKeyEvent>
QKeyEdit::QKeyEdit(QWidget *parent) :
QLineEdit(parent)
{
}
bool QKeyEdit::event(QEvent *e)
{
if(e->type() == QEvent::KeyPress)
{
QKeyEvent *ke = static_cast<QKeyEvent *>(e);
QKeySequence seq(ke->key());
setText(seq.toString());
return true;
}
return QLineEdit::event(e);
}

20
Qt/qkeyedit.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef QKEYEDIT_H
#define QKEYEDIT_H
#include <QLineEdit>
class QKeyEdit : public QLineEdit
{
Q_OBJECT
public:
explicit QKeyEdit(QWidget *parent = 0);
protected:
bool event(QEvent *e);
signals:
public slots:
};
#endif // QKEYEDIT_H

6
Qt/resources.qrc Normal file
View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/images">
<file>resources/psp.png</file>
<file>resources/psp_map.png</file>
</qresource>
</RCC>

BIN
Qt/resources/psp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
Qt/resources/psp_map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -321,6 +321,24 @@ namespace MainWindow
UpdateMenus();
break;
case ID_EMULATION_RESET:
for (int i=0; i<numCPUs; i++)
if (disasmWindow[i])
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
Sleep(100);//UGLY wait for event instead
for (int i=0; i<numCPUs; i++)
if (disasmWindow[i])
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_CLOSE, 0, 0);
for (int i=0; i<numCPUs; i++)
if (memoryWindow[i])
SendMessage(memoryWindow[i]->GetDlgHandle(), WM_CLOSE, 0, 0);
EmuThread_Stop();
EmuThread_Start(GetCurrentFilename());
break;
case ID_EMULATION_PAUSE:
for (int i=0; i<numCPUs; i++)