mirror of
https://github.com/libretro/ppsspp.git
synced 2024-12-16 21:56:48 +00:00
Merge branch 'master' into framebuffer-texture
This commit is contained in:
commit
2192029486
@ -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())
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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...
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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"},
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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?
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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"},
|
||||
};
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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),
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 ;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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)) {
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
156
Qt/PPSSPP.pro
156
Qt/PPSSPP.pro
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
237
Qt/controls.ui
237
Qt/controls.ui
@ -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>
|
||||
|
@ -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
21
Qt/qkeyedit.cpp
Normal 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
20
Qt/qkeyedit.h
Normal 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
6
Qt/resources.qrc
Normal 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
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
BIN
Qt/resources/psp_map.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
@ -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++)
|
||||
|
Loading…
Reference in New Issue
Block a user