set svn:eol-style=native for **.cpp
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1442 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
901fe7c00f
commit
49cfded60b
|
@ -1,279 +1,279 @@
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "x64Emitter.h"
|
#include "x64Emitter.h"
|
||||||
#include "ABI.h"
|
#include "ABI.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
// Shared code between Win64 and Unix64
|
// Shared code between Win64 and Unix64
|
||||||
// ====================================
|
// ====================================
|
||||||
|
|
||||||
// Sets up a __cdecl function.
|
// Sets up a __cdecl function.
|
||||||
void ABI_EmitPrologue(int maxCallParams)
|
void ABI_EmitPrologue(int maxCallParams)
|
||||||
{
|
{
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
// Don't really need to do anything
|
// Don't really need to do anything
|
||||||
#elif defined(_M_X64)
|
#elif defined(_M_X64)
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
int stacksize = ((maxCallParams + 1) & ~1)*8 + 8;
|
int stacksize = ((maxCallParams + 1) & ~1)*8 + 8;
|
||||||
// Set up a stack frame so that we can call functions
|
// Set up a stack frame so that we can call functions
|
||||||
// TODO: use maxCallParams
|
// TODO: use maxCallParams
|
||||||
SUB(64, R(RSP), Imm8(stacksize));
|
SUB(64, R(RSP), Imm8(stacksize));
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#error Arch not supported
|
#error Arch not supported
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void ABI_EmitEpilogue(int maxCallParams)
|
void ABI_EmitEpilogue(int maxCallParams)
|
||||||
{
|
{
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
RET();
|
RET();
|
||||||
#elif defined(_M_X64)
|
#elif defined(_M_X64)
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
int stacksize = ((maxCallParams+1)&~1)*8 + 8;
|
int stacksize = ((maxCallParams+1)&~1)*8 + 8;
|
||||||
ADD(64, R(RSP), Imm8(stacksize));
|
ADD(64, R(RSP), Imm8(stacksize));
|
||||||
#endif
|
#endif
|
||||||
RET();
|
RET();
|
||||||
#else
|
#else
|
||||||
#error Arch not supported
|
#error Arch not supported
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _M_IX86 // All32
|
#ifdef _M_IX86 // All32
|
||||||
|
|
||||||
// Shared code between Win32 and Unix32
|
// Shared code between Win32 and Unix32
|
||||||
// ====================================
|
// ====================================
|
||||||
|
|
||||||
void ABI_CallFunctionC(void *func, u32 param1) {
|
void ABI_CallFunctionC(void *func, u32 param1) {
|
||||||
ABI_AlignStack(1 * 4);
|
ABI_AlignStack(1 * 4);
|
||||||
PUSH(32, Imm32(param1));
|
PUSH(32, Imm32(param1));
|
||||||
CALL(func);
|
CALL(func);
|
||||||
ABI_RestoreStack(1 * 4);
|
ABI_RestoreStack(1 * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
|
void ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
|
||||||
ABI_AlignStack(2 * 4);
|
ABI_AlignStack(2 * 4);
|
||||||
PUSH(32, Imm32(param2));
|
PUSH(32, Imm32(param2));
|
||||||
PUSH(32, Imm32(param1));
|
PUSH(32, Imm32(param1));
|
||||||
CALL(func);
|
CALL(func);
|
||||||
ABI_RestoreStack(2 * 4);
|
ABI_RestoreStack(2 * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass a register as a paremeter.
|
// Pass a register as a paremeter.
|
||||||
void ABI_CallFunctionR(void *func, X64Reg reg1) {
|
void ABI_CallFunctionR(void *func, X64Reg reg1) {
|
||||||
ABI_AlignStack(1 * 4);
|
ABI_AlignStack(1 * 4);
|
||||||
PUSH(32, R(reg1));
|
PUSH(32, R(reg1));
|
||||||
CALL(func);
|
CALL(func);
|
||||||
ABI_RestoreStack(1 * 4);
|
ABI_RestoreStack(1 * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2)
|
void ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2)
|
||||||
{
|
{
|
||||||
ABI_AlignStack(2 * 4);
|
ABI_AlignStack(2 * 4);
|
||||||
PUSH(32, R(reg2));
|
PUSH(32, R(reg2));
|
||||||
PUSH(32, R(reg1));
|
PUSH(32, R(reg1));
|
||||||
CALL(func);
|
CALL(func);
|
||||||
ABI_RestoreStack(2 * 4);
|
ABI_RestoreStack(2 * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
|
void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
|
||||||
{
|
{
|
||||||
ABI_AlignStack(2 * 4);
|
ABI_AlignStack(2 * 4);
|
||||||
PUSH(32, arg1);
|
PUSH(32, arg1);
|
||||||
PUSH(32, Imm32(param2));
|
PUSH(32, Imm32(param2));
|
||||||
CALL(func);
|
CALL(func);
|
||||||
ABI_RestoreStack(2 * 4);
|
ABI_RestoreStack(2 * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||||
// Note: 4 * 4 = 16 bytes, so alignment is preserved.
|
// Note: 4 * 4 = 16 bytes, so alignment is preserved.
|
||||||
PUSH(EBP);
|
PUSH(EBP);
|
||||||
PUSH(EBX);
|
PUSH(EBX);
|
||||||
PUSH(ESI);
|
PUSH(ESI);
|
||||||
PUSH(EDI);
|
PUSH(EDI);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||||
POP(EDI);
|
POP(EDI);
|
||||||
POP(ESI);
|
POP(ESI);
|
||||||
POP(EBX);
|
POP(EBX);
|
||||||
POP(EBP);
|
POP(EBP);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize) {
|
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize) {
|
||||||
frameSize += 4; // reserve space for return address
|
frameSize += 4; // reserve space for return address
|
||||||
unsigned int alignedSize =
|
unsigned int alignedSize =
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
(frameSize + 15) & -16;
|
(frameSize + 15) & -16;
|
||||||
#else
|
#else
|
||||||
frameSize;
|
frameSize;
|
||||||
#endif
|
#endif
|
||||||
return alignedSize;
|
return alignedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ABI_AlignStack(unsigned int frameSize) {
|
void ABI_AlignStack(unsigned int frameSize) {
|
||||||
// Mac OS X requires the stack to be 16-byte aligned before every call.
|
// Mac OS X requires the stack to be 16-byte aligned before every call.
|
||||||
// Linux requires the stack to be 16-byte aligned before calls that put SSE
|
// Linux requires the stack to be 16-byte aligned before calls that put SSE
|
||||||
// vectors on the stack, but since we do not keep track of which calls do that,
|
// vectors on the stack, but since we do not keep track of which calls do that,
|
||||||
// it is effectively every call as well.
|
// it is effectively every call as well.
|
||||||
// Windows binaries compiled with MSVC do not have such a restriction, but I
|
// Windows binaries compiled with MSVC do not have such a restriction, but I
|
||||||
// expect that GCC on Windows acts the same as GCC on Linux in this respect.
|
// expect that GCC on Windows acts the same as GCC on Linux in this respect.
|
||||||
// It would be nice if someone could verify this.
|
// It would be nice if someone could verify this.
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
unsigned int fillSize =
|
unsigned int fillSize =
|
||||||
ABI_GetAlignedFrameSize(frameSize) - (frameSize + 4);
|
ABI_GetAlignedFrameSize(frameSize) - (frameSize + 4);
|
||||||
if (fillSize != 0) {
|
if (fillSize != 0) {
|
||||||
SUB(32, R(ESP), Imm8(fillSize));
|
SUB(32, R(ESP), Imm8(fillSize));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_RestoreStack(unsigned int frameSize) {
|
void ABI_RestoreStack(unsigned int frameSize) {
|
||||||
unsigned int alignedSize = ABI_GetAlignedFrameSize(frameSize);
|
unsigned int alignedSize = ABI_GetAlignedFrameSize(frameSize);
|
||||||
alignedSize -= 4; // return address is POPped at end of call
|
alignedSize -= 4; // return address is POPped at end of call
|
||||||
if (alignedSize != 0) {
|
if (alignedSize != 0) {
|
||||||
ADD(32, R(ESP), Imm8(alignedSize));
|
ADD(32, R(ESP), Imm8(alignedSize));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void ABI_CallFunctionC(void *func, u32 param1) {
|
void ABI_CallFunctionC(void *func, u32 param1) {
|
||||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||||
CALL(func);
|
CALL(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
|
void ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
|
||||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||||
CALL(func);
|
CALL(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass a register as a paremeter.
|
// Pass a register as a paremeter.
|
||||||
void ABI_CallFunctionR(void *func, X64Reg reg1) {
|
void ABI_CallFunctionR(void *func, X64Reg reg1) {
|
||||||
if (reg1 != ABI_PARAM1)
|
if (reg1 != ABI_PARAM1)
|
||||||
MOV(32, R(ABI_PARAM1), R(reg1));
|
MOV(32, R(ABI_PARAM1), R(reg1));
|
||||||
CALL(func);
|
CALL(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass a register as a paremeter.
|
// Pass a register as a paremeter.
|
||||||
void ABI_CallFunctionRR(void *func, X64Reg reg1, X64Reg reg2) {
|
void ABI_CallFunctionRR(void *func, X64Reg reg1, X64Reg reg2) {
|
||||||
if (reg1 != ABI_PARAM1)
|
if (reg1 != ABI_PARAM1)
|
||||||
MOV(32, R(ABI_PARAM1), R(reg1));
|
MOV(32, R(ABI_PARAM1), R(reg1));
|
||||||
if (reg2 != ABI_PARAM2)
|
if (reg2 != ABI_PARAM2)
|
||||||
MOV(32, R(ABI_PARAM2), R(reg2));
|
MOV(32, R(ABI_PARAM2), R(reg2));
|
||||||
CALL(func);
|
CALL(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
|
void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
|
||||||
{
|
{
|
||||||
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
||||||
MOV(32, R(ABI_PARAM1), arg1);
|
MOV(32, R(ABI_PARAM1), arg1);
|
||||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||||
CALL(func);
|
CALL(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize) {
|
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize) {
|
||||||
return frameSize;
|
return frameSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_AlignStack(unsigned int /*frameSize*/) {
|
void ABI_AlignStack(unsigned int /*frameSize*/) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_RestoreStack(unsigned int /*frameSize*/) {
|
void ABI_RestoreStack(unsigned int /*frameSize*/) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
// Win64 Specific Code
|
// Win64 Specific Code
|
||||||
// ====================================
|
// ====================================
|
||||||
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||||
//we only want to do this once
|
//we only want to do this once
|
||||||
PUSH(RBX);
|
PUSH(RBX);
|
||||||
PUSH(RSI);
|
PUSH(RSI);
|
||||||
PUSH(RDI);
|
PUSH(RDI);
|
||||||
PUSH(RBP);
|
PUSH(RBP);
|
||||||
PUSH(R12);
|
PUSH(R12);
|
||||||
PUSH(R13);
|
PUSH(R13);
|
||||||
PUSH(R14);
|
PUSH(R14);
|
||||||
PUSH(R15);
|
PUSH(R15);
|
||||||
//TODO: Also preserve XMM0-3?
|
//TODO: Also preserve XMM0-3?
|
||||||
SUB(64, R(RSP), Imm8(0x28));
|
SUB(64, R(RSP), Imm8(0x28));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||||
ADD(64, R(RSP), Imm8(0x28));
|
ADD(64, R(RSP), Imm8(0x28));
|
||||||
POP(R15);
|
POP(R15);
|
||||||
POP(R14);
|
POP(R14);
|
||||||
POP(R13);
|
POP(R13);
|
||||||
POP(R12);
|
POP(R12);
|
||||||
POP(RBP);
|
POP(RBP);
|
||||||
POP(RDI);
|
POP(RDI);
|
||||||
POP(RSI);
|
POP(RSI);
|
||||||
POP(RBX);
|
POP(RBX);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Win64 Specific Code
|
// Win64 Specific Code
|
||||||
// ====================================
|
// ====================================
|
||||||
void ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
void ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
||||||
PUSH(RCX);
|
PUSH(RCX);
|
||||||
PUSH(RDX);
|
PUSH(RDX);
|
||||||
PUSH(RSI);
|
PUSH(RSI);
|
||||||
PUSH(RDI);
|
PUSH(RDI);
|
||||||
PUSH(R8);
|
PUSH(R8);
|
||||||
PUSH(R9);
|
PUSH(R9);
|
||||||
PUSH(R10);
|
PUSH(R10);
|
||||||
PUSH(R11);
|
PUSH(R11);
|
||||||
//TODO: Also preserve XMM0-15?
|
//TODO: Also preserve XMM0-15?
|
||||||
SUB(64, R(RSP), Imm8(0x28));
|
SUB(64, R(RSP), Imm8(0x28));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
void ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
||||||
ADD(64, R(RSP), Imm8(0x28));
|
ADD(64, R(RSP), Imm8(0x28));
|
||||||
POP(R11);
|
POP(R11);
|
||||||
POP(R10);
|
POP(R10);
|
||||||
POP(R9);
|
POP(R9);
|
||||||
POP(R8);
|
POP(R8);
|
||||||
POP(RDI);
|
POP(RDI);
|
||||||
POP(RSI);
|
POP(RSI);
|
||||||
POP(RDX);
|
POP(RDX);
|
||||||
POP(RCX);
|
POP(RCX);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// Unix64 Specific Code
|
// Unix64 Specific Code
|
||||||
// ====================================
|
// ====================================
|
||||||
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||||
PUSH(RBX);
|
PUSH(RBX);
|
||||||
PUSH(RBP);
|
PUSH(RBP);
|
||||||
PUSH(R12);
|
PUSH(R12);
|
||||||
PUSH(R13);
|
PUSH(R13);
|
||||||
PUSH(R14);
|
PUSH(R14);
|
||||||
PUSH(R15);
|
PUSH(R15);
|
||||||
PUSH(R15); //just to align stack. duped push/pop doesn't hurt.
|
PUSH(R15); //just to align stack. duped push/pop doesn't hurt.
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||||
POP(R15);
|
POP(R15);
|
||||||
POP(R15);
|
POP(R15);
|
||||||
POP(R14);
|
POP(R14);
|
||||||
POP(R13);
|
POP(R13);
|
||||||
POP(R12);
|
POP(R12);
|
||||||
POP(RBP);
|
POP(RBP);
|
||||||
POP(RBX);
|
POP(RBX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
void ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
||||||
INT3();
|
INT3();
|
||||||
//not yet supported
|
//not yet supported
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
void ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
||||||
INT3();
|
INT3();
|
||||||
//not yet supported
|
//not yet supported
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,200 +1,200 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
|
#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
|
||||||
#define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset
|
#define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset
|
||||||
#define _interlockedbittestandset64 workaround_ms_header_bug_platform_sdk6_set64
|
#define _interlockedbittestandset64 workaround_ms_header_bug_platform_sdk6_set64
|
||||||
#define _interlockedbittestandreset64 workaround_ms_header_bug_platform_sdk6_reset64
|
#define _interlockedbittestandreset64 workaround_ms_header_bug_platform_sdk6_reset64
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
#undef _interlockedbittestandset
|
#undef _interlockedbittestandset
|
||||||
#undef _interlockedbittestandreset
|
#undef _interlockedbittestandreset
|
||||||
#undef _interlockedbittestandset64
|
#undef _interlockedbittestandset64
|
||||||
#undef _interlockedbittestandreset64
|
#undef _interlockedbittestandreset64
|
||||||
#else
|
#else
|
||||||
|
|
||||||
//#include <config/i386/cpuid.h>
|
//#include <config/i386/cpuid.h>
|
||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
|
|
||||||
static inline void do_cpuid(unsigned int *eax, unsigned int *ebx,
|
static inline void do_cpuid(unsigned int *eax, unsigned int *ebx,
|
||||||
unsigned int *ecx, unsigned int *edx)
|
unsigned int *ecx, unsigned int *edx)
|
||||||
{
|
{
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
__asm__("cpuid"
|
__asm__("cpuid"
|
||||||
: "=a" (*eax),
|
: "=a" (*eax),
|
||||||
"=b" (*ebx),
|
"=b" (*ebx),
|
||||||
"=c" (*ecx),
|
"=c" (*ecx),
|
||||||
"=d" (*edx)
|
"=d" (*edx)
|
||||||
: "a" (*eax)
|
: "a" (*eax)
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
// Note: EBX is reserved on Mac OS X and in PIC on Linux, so it has to be
|
// Note: EBX is reserved on Mac OS X and in PIC on Linux, so it has to be
|
||||||
// restored at the end of the asm block.
|
// restored at the end of the asm block.
|
||||||
__asm__(
|
__asm__(
|
||||||
"pushl %%ebx;"
|
"pushl %%ebx;"
|
||||||
"cpuid;"
|
"cpuid;"
|
||||||
"movl %%ebx,%1;"
|
"movl %%ebx,%1;"
|
||||||
"popl %%ebx;"
|
"popl %%ebx;"
|
||||||
: "=a" (*eax),
|
: "=a" (*eax),
|
||||||
"=r" (*ebx),
|
"=r" (*ebx),
|
||||||
"=c" (*ecx),
|
"=c" (*ecx),
|
||||||
"=d" (*edx)
|
"=d" (*edx)
|
||||||
: "a" (*eax)
|
: "a" (*eax)
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void __cpuid(int info[4], int x)
|
void __cpuid(int info[4], int x)
|
||||||
{
|
{
|
||||||
unsigned int eax = x, ebx = 0, ecx = 0, edx = 0;
|
unsigned int eax = x, ebx = 0, ecx = 0, edx = 0;
|
||||||
do_cpuid(&eax, &ebx, &ecx, &edx);
|
do_cpuid(&eax, &ebx, &ecx, &edx);
|
||||||
info[0] = eax;
|
info[0] = eax;
|
||||||
info[1] = ebx;
|
info[1] = ebx;
|
||||||
info[2] = ecx;
|
info[2] = ecx;
|
||||||
info[3] = edx;
|
info[3] = edx;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "CPUDetect.h"
|
#include "CPUDetect.h"
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
|
|
||||||
CPUInfo cpu_info;
|
CPUInfo cpu_info;
|
||||||
|
|
||||||
void CPUInfo::Detect()
|
void CPUInfo::Detect()
|
||||||
{
|
{
|
||||||
memset(this, 0, sizeof(*this));
|
memset(this, 0, sizeof(*this));
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
Mode64bit = false;
|
Mode64bit = false;
|
||||||
#elif defined (_M_X64)
|
#elif defined (_M_X64)
|
||||||
Mode64bit = true;
|
Mode64bit = true;
|
||||||
OS64bit = true;
|
OS64bit = true;
|
||||||
#endif
|
#endif
|
||||||
num_cores = 1;
|
num_cores = 1;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
BOOL f64 = FALSE;
|
BOOL f64 = FALSE;
|
||||||
OS64bit = IsWow64Process(GetCurrentProcess(), &f64) && f64;
|
OS64bit = IsWow64Process(GetCurrentProcess(), &f64) && f64;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Set obvious defaults, for extra safety
|
// Set obvious defaults, for extra safety
|
||||||
if (Mode64bit)
|
if (Mode64bit)
|
||||||
{
|
{
|
||||||
bSSE = true;
|
bSSE = true;
|
||||||
bSSE2 = true;
|
bSSE2 = true;
|
||||||
bLongMode = true;
|
bLongMode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assume CPU supports the CPUID instruction. Those that don't can barely boot modern OS:es anyway.
|
// Assume CPU supports the CPUID instruction. Those that don't can barely boot modern OS:es anyway.
|
||||||
int cpu_id[4];
|
int cpu_id[4];
|
||||||
memset(cpu_string, 0, sizeof(cpu_string));
|
memset(cpu_string, 0, sizeof(cpu_string));
|
||||||
|
|
||||||
// Detect CPU's CPUID capabilities, and grab cpu string
|
// Detect CPU's CPUID capabilities, and grab cpu string
|
||||||
__cpuid(cpu_id, 0x00000000);
|
__cpuid(cpu_id, 0x00000000);
|
||||||
u32 max_std_fn = cpu_id[0]; // EAX
|
u32 max_std_fn = cpu_id[0]; // EAX
|
||||||
*((int *)cpu_string) = cpu_id[1];
|
*((int *)cpu_string) = cpu_id[1];
|
||||||
*((int *)(cpu_string + 4)) = cpu_id[3];
|
*((int *)(cpu_string + 4)) = cpu_id[3];
|
||||||
*((int *)(cpu_string + 8)) = cpu_id[2];
|
*((int *)(cpu_string + 8)) = cpu_id[2];
|
||||||
__cpuid(cpu_id, 0x80000000);
|
__cpuid(cpu_id, 0x80000000);
|
||||||
u32 max_ex_fn = cpu_id[0];
|
u32 max_ex_fn = cpu_id[0];
|
||||||
if (!strcmp(cpu_string, "GenuineIntel"))
|
if (!strcmp(cpu_string, "GenuineIntel"))
|
||||||
vendor = VENDOR_INTEL;
|
vendor = VENDOR_INTEL;
|
||||||
else if (!strcmp(cpu_string, "AuthenticAMD"))
|
else if (!strcmp(cpu_string, "AuthenticAMD"))
|
||||||
vendor = VENDOR_AMD;
|
vendor = VENDOR_AMD;
|
||||||
else
|
else
|
||||||
vendor = VENDOR_OTHER;
|
vendor = VENDOR_OTHER;
|
||||||
|
|
||||||
// Set reasonable default brand string even if brand string not available.
|
// Set reasonable default brand string even if brand string not available.
|
||||||
strcpy(brand_string, cpu_string);
|
strcpy(brand_string, cpu_string);
|
||||||
|
|
||||||
// Detect family and other misc stuff.
|
// Detect family and other misc stuff.
|
||||||
bool HTT = false;
|
bool HTT = false;
|
||||||
int logical_cpu_count = 1;
|
int logical_cpu_count = 1;
|
||||||
if (max_std_fn >= 1) {
|
if (max_std_fn >= 1) {
|
||||||
__cpuid(cpu_id, 0x00000001);
|
__cpuid(cpu_id, 0x00000001);
|
||||||
logical_cpu_count = (cpu_id[1] >> 16) & 0xFF;
|
logical_cpu_count = (cpu_id[1] >> 16) & 0xFF;
|
||||||
if ((cpu_id[3] >> 28) & 1) {
|
if ((cpu_id[3] >> 28) & 1) {
|
||||||
// wtf, we get here on my core 2
|
// wtf, we get here on my core 2
|
||||||
HTT = true;
|
HTT = true;
|
||||||
}
|
}
|
||||||
if ((cpu_id[3] >> 25) & 1) bSSE = true;
|
if ((cpu_id[3] >> 25) & 1) bSSE = true;
|
||||||
if ((cpu_id[3] >> 26) & 1) bSSE2 = true;
|
if ((cpu_id[3] >> 26) & 1) bSSE2 = true;
|
||||||
if (cpu_id[2] & 1) bSSE3 = true;
|
if (cpu_id[2] & 1) bSSE3 = true;
|
||||||
if ((cpu_id[2] >> 9) & 1) bSSSE3 = true;
|
if ((cpu_id[2] >> 9) & 1) bSSSE3 = true;
|
||||||
if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true;
|
if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true;
|
||||||
if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true;
|
if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true;
|
||||||
}
|
}
|
||||||
if (max_ex_fn >= 0x80000004) {
|
if (max_ex_fn >= 0x80000004) {
|
||||||
// Extract brand string
|
// Extract brand string
|
||||||
__cpuid(cpu_id, 0x80000002);
|
__cpuid(cpu_id, 0x80000002);
|
||||||
memcpy(brand_string, cpu_id, sizeof(cpu_id));
|
memcpy(brand_string, cpu_id, sizeof(cpu_id));
|
||||||
__cpuid(cpu_id, 0x80000003);
|
__cpuid(cpu_id, 0x80000003);
|
||||||
memcpy(brand_string + 16, cpu_id, sizeof(cpu_id));
|
memcpy(brand_string + 16, cpu_id, sizeof(cpu_id));
|
||||||
__cpuid(cpu_id, 0x80000004);
|
__cpuid(cpu_id, 0x80000004);
|
||||||
memcpy(brand_string + 32, cpu_id, sizeof(cpu_id));
|
memcpy(brand_string + 32, cpu_id, sizeof(cpu_id));
|
||||||
}
|
}
|
||||||
if (max_ex_fn >= 0x80000001) {
|
if (max_ex_fn >= 0x80000001) {
|
||||||
// Check for more features.
|
// Check for more features.
|
||||||
__cpuid(cpu_id, 0x80000001);
|
__cpuid(cpu_id, 0x80000001);
|
||||||
bool cmp_legacy = false;
|
bool cmp_legacy = false;
|
||||||
if (cpu_id[2] & 1) bLAHFSAHF64 = true;
|
if (cpu_id[2] & 1) bLAHFSAHF64 = true;
|
||||||
if (cpu_id[2] & 2) cmp_legacy = true; //wtf is this?
|
if (cpu_id[2] & 2) cmp_legacy = true; //wtf is this?
|
||||||
if ((cpu_id[3] >> 29) & 1) bLongMode = true;
|
if ((cpu_id[3] >> 29) & 1) bLongMode = true;
|
||||||
}
|
}
|
||||||
if (max_ex_fn >= 0x80000008) {
|
if (max_ex_fn >= 0x80000008) {
|
||||||
// Get number of cores. This is a bit complicated. Following AMD manual here.
|
// Get number of cores. This is a bit complicated. Following AMD manual here.
|
||||||
__cpuid(cpu_id, 0x80000008);
|
__cpuid(cpu_id, 0x80000008);
|
||||||
int apic_id_core_id_size = (cpu_id[2] >> 12) & 0xF;
|
int apic_id_core_id_size = (cpu_id[2] >> 12) & 0xF;
|
||||||
if (apic_id_core_id_size == 0) {
|
if (apic_id_core_id_size == 0) {
|
||||||
// Use what AMD calls the "legacy method" to determine # of cores.
|
// Use what AMD calls the "legacy method" to determine # of cores.
|
||||||
if (HTT) {
|
if (HTT) {
|
||||||
num_cores = logical_cpu_count;
|
num_cores = logical_cpu_count;
|
||||||
} else {
|
} else {
|
||||||
num_cores = 1;
|
num_cores = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use AMD's new method.
|
// Use AMD's new method.
|
||||||
num_cores = (cpu_id[2] & 0xFF) + 1;
|
num_cores = (cpu_id[2] & 0xFF) + 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Wild guess
|
// Wild guess
|
||||||
if (logical_cpu_count)
|
if (logical_cpu_count)
|
||||||
num_cores = logical_cpu_count;
|
num_cores = logical_cpu_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CPUInfo::Summarize()
|
std::string CPUInfo::Summarize()
|
||||||
{
|
{
|
||||||
std::string sum;
|
std::string sum;
|
||||||
if (num_cores == 1)
|
if (num_cores == 1)
|
||||||
sum = StringFromFormat("%s, %i core, ", cpu_string, num_cores);
|
sum = StringFromFormat("%s, %i core, ", cpu_string, num_cores);
|
||||||
else
|
else
|
||||||
sum = StringFromFormat("%s, %i cores, ", cpu_string, num_cores);
|
sum = StringFromFormat("%s, %i cores, ", cpu_string, num_cores);
|
||||||
if (bSSE) sum += "SSE";
|
if (bSSE) sum += "SSE";
|
||||||
if (bSSE2) sum += ", SSE2";
|
if (bSSE2) sum += ", SSE2";
|
||||||
if (bSSE3) sum += ", SSE3";
|
if (bSSE3) sum += ", SSE3";
|
||||||
if (bSSSE3) sum += ", SSSE3";
|
if (bSSSE3) sum += ", SSSE3";
|
||||||
if (bSSE4_1) sum += ", SSE4.1";
|
if (bSSE4_1) sum += ", SSE4.1";
|
||||||
if (bSSE4_2) sum += ", SSE4.2";
|
if (bSSE4_2) sum += ", SSE4.2";
|
||||||
if (bLongMode) sum += ", 64-bit support";
|
if (bLongMode) sum += ", 64-bit support";
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
|
@ -1,113 +1,113 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
static PanicAlertHandler panic_handler = 0;
|
static PanicAlertHandler panic_handler = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterPanicAlertHandler(PanicAlertHandler handler)
|
void RegisterPanicAlertHandler(PanicAlertHandler handler)
|
||||||
{
|
{
|
||||||
panic_handler = handler;
|
panic_handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PanicAlert(const char* format, ...)
|
void PanicAlert(const char* format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
|
|
||||||
if (panic_handler)
|
if (panic_handler)
|
||||||
{
|
{
|
||||||
std::string msg;
|
std::string msg;
|
||||||
StringFromFormatV(&msg, format, args);
|
StringFromFormatV(&msg, format, args);
|
||||||
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
|
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
|
||||||
panic_handler(msg.c_str(), false);
|
panic_handler(msg.c_str(), false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::string msg;
|
std::string msg;
|
||||||
StringFromFormatV(&msg, format, args);
|
StringFromFormatV(&msg, format, args);
|
||||||
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
|
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
|
||||||
MessageBox(0, msg.c_str(), "PANIC!", MB_ICONWARNING);
|
MessageBox(0, msg.c_str(), "PANIC!", MB_ICONWARNING);
|
||||||
#elif __GNUC__
|
#elif __GNUC__
|
||||||
//#error Do a messagebox!
|
//#error Do a messagebox!
|
||||||
vprintf(format, args);
|
vprintf(format, args);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
// asm ("int $3") ;
|
// asm ("int $3") ;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PanicYesNo(const char* format, ...)
|
bool PanicYesNo(const char* format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
bool retval;
|
bool retval;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::string msg;
|
std::string msg;
|
||||||
StringFromFormatV(&msg, format, args);
|
StringFromFormatV(&msg, format, args);
|
||||||
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
|
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
|
||||||
retval = IDYES == MessageBox(0, msg.c_str(), "PANIC! Continue?", MB_ICONQUESTION | MB_YESNO);
|
retval = IDYES == MessageBox(0, msg.c_str(), "PANIC! Continue?", MB_ICONQUESTION | MB_YESNO);
|
||||||
#elif __GNUC__
|
#elif __GNUC__
|
||||||
//vprintf(format, args);
|
//vprintf(format, args);
|
||||||
return(true); //#error Do a messagebox!
|
return(true); //#error Do a messagebox!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return(retval);
|
return(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool AskYesNo(const char* format, ...)
|
bool AskYesNo(const char* format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
bool retval;
|
bool retval;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::string msg;
|
std::string msg;
|
||||||
StringFromFormatV(&msg, format, args);
|
StringFromFormatV(&msg, format, args);
|
||||||
LOG(MASTER_LOG, "ASK: %s", msg.c_str());
|
LOG(MASTER_LOG, "ASK: %s", msg.c_str());
|
||||||
retval = IDYES == MessageBox(0, msg.c_str(), "Dolphin", MB_ICONQUESTION | MB_YESNO);
|
retval = IDYES == MessageBox(0, msg.c_str(), "Dolphin", MB_ICONQUESTION | MB_YESNO);
|
||||||
#elif __GNUC__
|
#elif __GNUC__
|
||||||
//vprintf(format, args);
|
//vprintf(format, args);
|
||||||
return(true); //#error Do a messagebox!
|
return(true); //#error Do a messagebox!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return(retval);
|
return(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standard implementation of logging - simply print to standard output.
|
// Standard implementation of logging - simply print to standard output.
|
||||||
// Programs are welcome to override this.
|
// Programs are welcome to override this.
|
||||||
/*
|
/*
|
||||||
void __Log(int logNumber, const char *text, ...)
|
void __Log(int logNumber, const char *text, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, text);
|
va_start(args, text);
|
||||||
vprintf(text, args);
|
vprintf(text, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}*/
|
}*/
|
||||||
|
|
|
@ -1,57 +1,57 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winioctl.h>
|
#include <winioctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void GetAllRemovableDrives(std::vector<std::string> *drives) {
|
void GetAllRemovableDrives(std::vector<std::string> *drives) {
|
||||||
drives->clear();
|
drives->clear();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE hDisk;
|
HANDLE hDisk;
|
||||||
DISK_GEOMETRY diskGeometry;
|
DISK_GEOMETRY diskGeometry;
|
||||||
|
|
||||||
for (int i = 'A'; i < 'Z'; i++)
|
for (int i = 'A'; i < 'Z'; i++)
|
||||||
{
|
{
|
||||||
char path[MAX_PATH];
|
char path[MAX_PATH];
|
||||||
sprintf(path, "\\\\.\\%c:", i);
|
sprintf(path, "\\\\.\\%c:", i);
|
||||||
hDisk = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
hDisk = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||||
if (hDisk != INVALID_HANDLE_VALUE)
|
if (hDisk != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
DWORD dwBytes;
|
DWORD dwBytes;
|
||||||
DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &diskGeometry, sizeof(DISK_GEOMETRY), &dwBytes, NULL);
|
DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &diskGeometry, sizeof(DISK_GEOMETRY), &dwBytes, NULL);
|
||||||
// Only proceed if disk is a removable media
|
// Only proceed if disk is a removable media
|
||||||
if (diskGeometry.MediaType == RemovableMedia)
|
if (diskGeometry.MediaType == RemovableMedia)
|
||||||
{
|
{
|
||||||
if (diskGeometry.BytesPerSector == 2048) {
|
if (diskGeometry.BytesPerSector == 2048) {
|
||||||
// Probably CD/DVD drive.
|
// Probably CD/DVD drive.
|
||||||
// "Remove" the "\\.\" part of the path and return it.
|
// "Remove" the "\\.\" part of the path and return it.
|
||||||
drives->push_back(path + 4);
|
drives->push_back(path + 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseHandle(hDisk);
|
CloseHandle(hDisk);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// TODO
|
// TODO
|
||||||
// stat("/media/cdrom") or whatever etc etc
|
// stat("/media/cdrom") or whatever etc etc
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,151 +1,151 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "DynamicLibrary.h"
|
#include "DynamicLibrary.h"
|
||||||
#include "../../Core/Src/PowerPC/PowerPC.h"
|
#include "../../Core/Src/PowerPC/PowerPC.h"
|
||||||
|
|
||||||
DynamicLibrary::DynamicLibrary()
|
DynamicLibrary::DynamicLibrary()
|
||||||
{
|
{
|
||||||
library = 0;
|
library = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::string GetLastErrorAsString()
|
std::string GetLastErrorAsString()
|
||||||
{
|
{
|
||||||
LPVOID lpMsgBuf = 0;
|
LPVOID lpMsgBuf = 0;
|
||||||
DWORD error = GetLastError();
|
DWORD error = GetLastError();
|
||||||
FormatMessage(
|
FormatMessage(
|
||||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||||
NULL,
|
NULL,
|
||||||
error,
|
error,
|
||||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||||
(LPTSTR) &lpMsgBuf,
|
(LPTSTR) &lpMsgBuf,
|
||||||
0, NULL);
|
0, NULL);
|
||||||
std::string s;
|
std::string s;
|
||||||
if (lpMsgBuf)
|
if (lpMsgBuf)
|
||||||
{
|
{
|
||||||
s = ((char *)lpMsgBuf);
|
s = ((char *)lpMsgBuf);
|
||||||
LocalFree(lpMsgBuf);
|
LocalFree(lpMsgBuf);
|
||||||
} else {
|
} else {
|
||||||
s = StringFromFormat("(unknown error %08x)", error);
|
s = StringFromFormat("(unknown error %08x)", error);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
/* Loading means loading the dll with LoadLibrary() to get an instance to the dll.
|
/* Loading means loading the dll with LoadLibrary() to get an instance to the dll.
|
||||||
This is done when Dolphin is started to determine which dlls are good, and
|
This is done when Dolphin is started to determine which dlls are good, and
|
||||||
before opening the Config and Debugging windowses from Plugin.cpp and
|
before opening the Config and Debugging windowses from Plugin.cpp and
|
||||||
before opening the dll for running the emulation in Video_...cpp in Core. */
|
before opening the dll for running the emulation in Video_...cpp in Core. */
|
||||||
// -----------------------
|
// -----------------------
|
||||||
int DynamicLibrary::Load(const char* filename)
|
int DynamicLibrary::Load(const char* filename)
|
||||||
{
|
{
|
||||||
if (!filename || strlen(filename) == 0)
|
if (!filename || strlen(filename) == 0)
|
||||||
{
|
{
|
||||||
LOG(MASTER_LOG, "Missing filename of dynamic library to load");
|
LOG(MASTER_LOG, "Missing filename of dynamic library to load");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
LOG(MASTER_LOG, "Trying to load library %s", filename);
|
LOG(MASTER_LOG, "Trying to load library %s", filename);
|
||||||
|
|
||||||
if (IsLoaded())
|
if (IsLoaded())
|
||||||
{
|
{
|
||||||
LOG(MASTER_LOG, "Trying to load already loaded library %s", filename);
|
LOG(MASTER_LOG, "Trying to load already loaded library %s", filename);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
library = LoadLibrary(filename);
|
library = LoadLibrary(filename);
|
||||||
if (!library) {
|
if (!library) {
|
||||||
LOG(MASTER_LOG, "Error loading DLL %s: %s", filename, GetLastErrorAsString().c_str());
|
LOG(MASTER_LOG, "Error loading DLL %s: %s", filename, GetLastErrorAsString().c_str());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
library = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
|
library = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
|
||||||
if (!library)
|
if (!library)
|
||||||
{
|
{
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
LOG(MASTER_LOG, "Error loading DLL %s: %s", filename, dlerror());
|
LOG(MASTER_LOG, "Error loading DLL %s: %s", filename, dlerror());
|
||||||
#else
|
#else
|
||||||
printf("Error loading DLL %s: %s", filename, dlerror());
|
printf("Error loading DLL %s: %s", filename, dlerror());
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
library_file = filename;
|
library_file = filename;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DynamicLibrary::Unload()
|
void DynamicLibrary::Unload()
|
||||||
{
|
{
|
||||||
if (!IsLoaded())
|
if (!IsLoaded())
|
||||||
{
|
{
|
||||||
PanicAlert("Trying to unload non-loaded library");
|
PanicAlert("Trying to unload non-loaded library");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/* TEMPORARY SOLUTION: To prevent that Dolphin hangs when a game is stopped
|
/* TEMPORARY SOLUTION: To prevent that Dolphin hangs when a game is stopped
|
||||||
or when we try to close Dolphin. It's possible that it only occur when we render
|
or when we try to close Dolphin. It's possible that it only occur when we render
|
||||||
to the main window. And sometimes FreeLibrary works without any problem, so
|
to the main window. And sometimes FreeLibrary works without any problem, so
|
||||||
don't remove this just because it doesn't hang once. I could not find the
|
don't remove this just because it doesn't hang once. I could not find the
|
||||||
actual cause of it. */
|
actual cause of it. */
|
||||||
if( ! (library_file.find("OGL.") != std::string::npos) && !PowerPC::CPU_POWERDOWN)
|
if( ! (library_file.find("OGL.") != std::string::npos) && !PowerPC::CPU_POWERDOWN)
|
||||||
FreeLibrary(library);
|
FreeLibrary(library);
|
||||||
#else
|
#else
|
||||||
dlclose(library);
|
dlclose(library);
|
||||||
#endif
|
#endif
|
||||||
library = 0;
|
library = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void* DynamicLibrary::Get(const char* funcname) const
|
void* DynamicLibrary::Get(const char* funcname) const
|
||||||
{
|
{
|
||||||
void* retval;
|
void* retval;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (!library)
|
if (!library)
|
||||||
{
|
{
|
||||||
PanicAlert("Can't find function %s - Library not loaded.");
|
PanicAlert("Can't find function %s - Library not loaded.");
|
||||||
}
|
}
|
||||||
retval = GetProcAddress(library, funcname);
|
retval = GetProcAddress(library, funcname);
|
||||||
//if (!retval)
|
//if (!retval)
|
||||||
//{
|
//{
|
||||||
// PanicAlert("Did not find function %s in library %s.", funcname, library_file.c_str());
|
// PanicAlert("Did not find function %s in library %s.", funcname, library_file.c_str());
|
||||||
//}
|
//}
|
||||||
#else
|
#else
|
||||||
retval = dlsym(library, funcname);
|
retval = dlsym(library, funcname);
|
||||||
|
|
||||||
if (!retval)
|
if (!retval)
|
||||||
{
|
{
|
||||||
printf("Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), dlerror());
|
printf("Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), dlerror());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,437 +1,437 @@
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com
|
// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com
|
||||||
// For companies(Austin,TX): If you would like to get my resume, send an email.
|
// For companies(Austin,TX): If you would like to get my resume, send an email.
|
||||||
//
|
//
|
||||||
// The source is free, but if you want to use it, mention my name and e-mail address
|
// The source is free, but if you want to use it, mention my name and e-mail address
|
||||||
//
|
//
|
||||||
// History:
|
// History:
|
||||||
// 1.0 Initial version Zoltan Csizmadia
|
// 1.0 Initial version Zoltan Csizmadia
|
||||||
// 1.1 WhineCube version Masken
|
// 1.1 WhineCube version Masken
|
||||||
// 1.2 Dolphin version Masken
|
// 1.2 Dolphin version Masken
|
||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// ExtendedTrace.cpp
|
// ExtendedTrace.cpp
|
||||||
//
|
//
|
||||||
|
|
||||||
// Include StdAfx.h, if you're using precompiled
|
// Include StdAfx.h, if you're using precompiled
|
||||||
// header through StdAfx.h
|
// header through StdAfx.h
|
||||||
//#include "stdafx.h"
|
//#include "stdafx.h"
|
||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "ExtendedTrace.h"
|
#include "ExtendedTrace.h"
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
#include <ImageHlp.h>
|
#include <ImageHlp.h>
|
||||||
|
|
||||||
#define BUFFERSIZE 0x200
|
#define BUFFERSIZE 0x200
|
||||||
#pragma warning(disable:4996)
|
#pragma warning(disable:4996)
|
||||||
|
|
||||||
// Unicode safe char* -> TCHAR* conversion
|
// Unicode safe char* -> TCHAR* conversion
|
||||||
void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut )
|
void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut )
|
||||||
{
|
{
|
||||||
#if defined(UNICODE)||defined(_UNICODE)
|
#if defined(UNICODE)||defined(_UNICODE)
|
||||||
ULONG index = 0;
|
ULONG index = 0;
|
||||||
PCSTR lpAct = lpszIn;
|
PCSTR lpAct = lpszIn;
|
||||||
|
|
||||||
for( ; ; lpAct++ )
|
for( ; ; lpAct++ )
|
||||||
{
|
{
|
||||||
lpszOut[index++] = (TCHAR)(*lpAct);
|
lpszOut[index++] = (TCHAR)(*lpAct);
|
||||||
if ( *lpAct == 0 )
|
if ( *lpAct == 0 )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// This is trivial :)
|
// This is trivial :)
|
||||||
strcpy( lpszOut, lpszIn );
|
strcpy( lpszOut, lpszIn );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's figure out the path for the symbol files
|
// Let's figure out the path for the symbol files
|
||||||
// Search path= ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" + lpszIniPath
|
// Search path= ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" + lpszIniPath
|
||||||
// Note: There is no size check for lpszSymbolPath!
|
// Note: There is no size check for lpszSymbolPath!
|
||||||
static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath )
|
static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath )
|
||||||
{
|
{
|
||||||
CHAR lpszPath[BUFFERSIZE];
|
CHAR lpszPath[BUFFERSIZE];
|
||||||
|
|
||||||
// Creating the default path
|
// Creating the default path
|
||||||
// ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;"
|
// ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;"
|
||||||
strcpy( lpszSymbolPath, "." );
|
strcpy( lpszSymbolPath, "." );
|
||||||
|
|
||||||
// environment variable _NT_SYMBOL_PATH
|
// environment variable _NT_SYMBOL_PATH
|
||||||
if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
|
if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
|
||||||
{
|
{
|
||||||
strcat( lpszSymbolPath, ";" );
|
strcat( lpszSymbolPath, ";" );
|
||||||
strcat( lpszSymbolPath, lpszPath );
|
strcat( lpszSymbolPath, lpszPath );
|
||||||
}
|
}
|
||||||
|
|
||||||
// environment variable _NT_ALTERNATE_SYMBOL_PATH
|
// environment variable _NT_ALTERNATE_SYMBOL_PATH
|
||||||
if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
|
if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
|
||||||
{
|
{
|
||||||
strcat( lpszSymbolPath, ";" );
|
strcat( lpszSymbolPath, ";" );
|
||||||
strcat( lpszSymbolPath, lpszPath );
|
strcat( lpszSymbolPath, lpszPath );
|
||||||
}
|
}
|
||||||
|
|
||||||
// environment variable SYSTEMROOT
|
// environment variable SYSTEMROOT
|
||||||
if ( GetEnvironmentVariableA( "SYSTEMROOT", lpszPath, BUFFERSIZE ) )
|
if ( GetEnvironmentVariableA( "SYSTEMROOT", lpszPath, BUFFERSIZE ) )
|
||||||
{
|
{
|
||||||
strcat( lpszSymbolPath, ";" );
|
strcat( lpszSymbolPath, ";" );
|
||||||
strcat( lpszSymbolPath, lpszPath );
|
strcat( lpszSymbolPath, lpszPath );
|
||||||
strcat( lpszSymbolPath, ";" );
|
strcat( lpszSymbolPath, ";" );
|
||||||
|
|
||||||
// SYSTEMROOT\System32
|
// SYSTEMROOT\System32
|
||||||
strcat( lpszSymbolPath, lpszPath );
|
strcat( lpszSymbolPath, lpszPath );
|
||||||
strcat( lpszSymbolPath, "\\System32" );
|
strcat( lpszSymbolPath, "\\System32" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add user defined path
|
// Add user defined path
|
||||||
if ( lpszIniPath != NULL )
|
if ( lpszIniPath != NULL )
|
||||||
if ( lpszIniPath[0] != '\0' )
|
if ( lpszIniPath[0] != '\0' )
|
||||||
{
|
{
|
||||||
strcat( lpszSymbolPath, ";" );
|
strcat( lpszSymbolPath, ";" );
|
||||||
strcat( lpszSymbolPath, lpszIniPath );
|
strcat( lpszSymbolPath, lpszIniPath );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uninitialize the loaded symbol files
|
// Uninitialize the loaded symbol files
|
||||||
BOOL UninitSymInfo() {
|
BOOL UninitSymInfo() {
|
||||||
return SymCleanup( GetCurrentProcess() );
|
return SymCleanup( GetCurrentProcess() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the symbol files
|
// Initializes the symbol files
|
||||||
BOOL InitSymInfo( PCSTR lpszInitialSymbolPath )
|
BOOL InitSymInfo( PCSTR lpszInitialSymbolPath )
|
||||||
{
|
{
|
||||||
CHAR lpszSymbolPath[BUFFERSIZE];
|
CHAR lpszSymbolPath[BUFFERSIZE];
|
||||||
DWORD symOptions = SymGetOptions();
|
DWORD symOptions = SymGetOptions();
|
||||||
|
|
||||||
symOptions |= SYMOPT_LOAD_LINES;
|
symOptions |= SYMOPT_LOAD_LINES;
|
||||||
symOptions &= ~SYMOPT_UNDNAME;
|
symOptions &= ~SYMOPT_UNDNAME;
|
||||||
SymSetOptions( symOptions );
|
SymSetOptions( symOptions );
|
||||||
InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath );
|
InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath );
|
||||||
|
|
||||||
return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE);
|
return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the module name from a given address
|
// Get the module name from a given address
|
||||||
static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule )
|
static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule )
|
||||||
{
|
{
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
IMAGEHLP_MODULE moduleInfo;
|
IMAGEHLP_MODULE moduleInfo;
|
||||||
|
|
||||||
::ZeroMemory( &moduleInfo, sizeof(moduleInfo) );
|
::ZeroMemory( &moduleInfo, sizeof(moduleInfo) );
|
||||||
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
|
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
|
||||||
|
|
||||||
if ( SymGetModuleInfo( GetCurrentProcess(), (DWORD)address, &moduleInfo ) )
|
if ( SymGetModuleInfo( GetCurrentProcess(), (DWORD)address, &moduleInfo ) )
|
||||||
{
|
{
|
||||||
// Got it!
|
// Got it!
|
||||||
PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule );
|
PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule );
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// Not found :(
|
// Not found :(
|
||||||
_tcscpy( lpszModule, _T("?") );
|
_tcscpy( lpszModule, _T("?") );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get function prototype and parameter info from ip address and stack address
|
// Get function prototype and parameter info from ip address and stack address
|
||||||
static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol )
|
static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol )
|
||||||
{
|
{
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
DWORD dwDisp = 0;
|
DWORD dwDisp = 0;
|
||||||
DWORD dwSymSize = 10000;
|
DWORD dwSymSize = 10000;
|
||||||
TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?");
|
TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?");
|
||||||
CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?";
|
CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?";
|
||||||
LPTSTR lpszParamSep = NULL;
|
LPTSTR lpszParamSep = NULL;
|
||||||
LPTSTR lpszParsed = lpszUnDSymbol;
|
LPTSTR lpszParsed = lpszUnDSymbol;
|
||||||
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize );
|
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize );
|
||||||
|
|
||||||
::ZeroMemory( pSym, dwSymSize );
|
::ZeroMemory( pSym, dwSymSize );
|
||||||
pSym->SizeOfStruct = dwSymSize;
|
pSym->SizeOfStruct = dwSymSize;
|
||||||
pSym->MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL);
|
pSym->MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL);
|
||||||
|
|
||||||
// Set the default to unknown
|
// Set the default to unknown
|
||||||
_tcscpy( lpszSymbol, _T("?") );
|
_tcscpy( lpszSymbol, _T("?") );
|
||||||
|
|
||||||
// Get symbol info for IP
|
// Get symbol info for IP
|
||||||
#ifndef _M_X64
|
#ifndef _M_X64
|
||||||
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) )
|
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) )
|
||||||
#else
|
#else
|
||||||
//makes it compile but hell im not sure if this works...
|
//makes it compile but hell im not sure if this works...
|
||||||
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) )
|
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
// Make the symbol readable for humans
|
// Make the symbol readable for humans
|
||||||
UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
|
UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
|
||||||
UNDNAME_COMPLETE |
|
UNDNAME_COMPLETE |
|
||||||
UNDNAME_NO_THISTYPE |
|
UNDNAME_NO_THISTYPE |
|
||||||
UNDNAME_NO_SPECIAL_SYMS |
|
UNDNAME_NO_SPECIAL_SYMS |
|
||||||
UNDNAME_NO_MEMBER_TYPE |
|
UNDNAME_NO_MEMBER_TYPE |
|
||||||
UNDNAME_NO_MS_KEYWORDS |
|
UNDNAME_NO_MS_KEYWORDS |
|
||||||
UNDNAME_NO_ACCESS_SPECIFIERS );
|
UNDNAME_NO_ACCESS_SPECIFIERS );
|
||||||
|
|
||||||
// Symbol information is ANSI string
|
// Symbol information is ANSI string
|
||||||
PCSTR2LPTSTR( lpszNonUnicodeUnDSymbol, lpszUnDSymbol );
|
PCSTR2LPTSTR( lpszNonUnicodeUnDSymbol, lpszUnDSymbol );
|
||||||
|
|
||||||
// I am just smarter than the symbol file :)
|
// I am just smarter than the symbol file :)
|
||||||
if ( _tcscmp(lpszUnDSymbol, _T("_WinMain@16")) == 0 )
|
if ( _tcscmp(lpszUnDSymbol, _T("_WinMain@16")) == 0 )
|
||||||
_tcscpy(lpszUnDSymbol, _T("WinMain(HINSTANCE,HINSTANCE,LPCTSTR,int)"));
|
_tcscpy(lpszUnDSymbol, _T("WinMain(HINSTANCE,HINSTANCE,LPCTSTR,int)"));
|
||||||
else
|
else
|
||||||
if ( _tcscmp(lpszUnDSymbol, _T("_main")) == 0 )
|
if ( _tcscmp(lpszUnDSymbol, _T("_main")) == 0 )
|
||||||
_tcscpy(lpszUnDSymbol, _T("main(int,TCHAR * *)"));
|
_tcscpy(lpszUnDSymbol, _T("main(int,TCHAR * *)"));
|
||||||
else
|
else
|
||||||
if ( _tcscmp(lpszUnDSymbol, _T("_mainCRTStartup")) == 0 )
|
if ( _tcscmp(lpszUnDSymbol, _T("_mainCRTStartup")) == 0 )
|
||||||
_tcscpy(lpszUnDSymbol, _T("mainCRTStartup()"));
|
_tcscpy(lpszUnDSymbol, _T("mainCRTStartup()"));
|
||||||
else
|
else
|
||||||
if ( _tcscmp(lpszUnDSymbol, _T("_wmain")) == 0 )
|
if ( _tcscmp(lpszUnDSymbol, _T("_wmain")) == 0 )
|
||||||
_tcscpy(lpszUnDSymbol, _T("wmain(int,TCHAR * *,TCHAR * *)"));
|
_tcscpy(lpszUnDSymbol, _T("wmain(int,TCHAR * *,TCHAR * *)"));
|
||||||
else
|
else
|
||||||
if ( _tcscmp(lpszUnDSymbol, _T("_wmainCRTStartup")) == 0 )
|
if ( _tcscmp(lpszUnDSymbol, _T("_wmainCRTStartup")) == 0 )
|
||||||
_tcscpy(lpszUnDSymbol, _T("wmainCRTStartup()"));
|
_tcscpy(lpszUnDSymbol, _T("wmainCRTStartup()"));
|
||||||
|
|
||||||
lpszSymbol[0] = _T('\0');
|
lpszSymbol[0] = _T('\0');
|
||||||
|
|
||||||
// Let's go through the stack, and modify the function prototype, and insert the actual
|
// Let's go through the stack, and modify the function prototype, and insert the actual
|
||||||
// parameter values from the stack
|
// parameter values from the stack
|
||||||
if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL)
|
if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL)
|
||||||
{
|
{
|
||||||
ULONG index = 0;
|
ULONG index = 0;
|
||||||
for( ; ; index++ )
|
for( ; ; index++ )
|
||||||
{
|
{
|
||||||
lpszParamSep = _tcschr( lpszParsed, _T(',') );
|
lpszParamSep = _tcschr( lpszParsed, _T(',') );
|
||||||
if ( lpszParamSep == NULL )
|
if ( lpszParamSep == NULL )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
*lpszParamSep = _T('\0');
|
*lpszParamSep = _T('\0');
|
||||||
|
|
||||||
_tcscat( lpszSymbol, lpszParsed );
|
_tcscat( lpszSymbol, lpszParsed );
|
||||||
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X,"), *((ULONG*)(stackAddress) + 2 + index) );
|
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X,"), *((ULONG*)(stackAddress) + 2 + index) );
|
||||||
|
|
||||||
lpszParsed = lpszParamSep + 1;
|
lpszParsed = lpszParamSep + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lpszParamSep = _tcschr( lpszParsed, _T(')') );
|
lpszParamSep = _tcschr( lpszParsed, _T(')') );
|
||||||
if ( lpszParamSep != NULL )
|
if ( lpszParamSep != NULL )
|
||||||
{
|
{
|
||||||
*lpszParamSep = _T('\0');
|
*lpszParamSep = _T('\0');
|
||||||
|
|
||||||
_tcscat( lpszSymbol, lpszParsed );
|
_tcscat( lpszSymbol, lpszParsed );
|
||||||
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X)"), *((ULONG*)(stackAddress) + 2 + index) );
|
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X)"), *((ULONG*)(stackAddress) + 2 + index) );
|
||||||
|
|
||||||
lpszParsed = lpszParamSep + 1;
|
lpszParsed = lpszParamSep + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_tcscat( lpszSymbol, lpszParsed );
|
_tcscat( lpszSymbol, lpszParsed );
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
GlobalFree( pSym );
|
GlobalFree( pSym );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get source file name and line number from IP address
|
// Get source file name and line number from IP address
|
||||||
// The output format is: "sourcefile(linenumber)" or
|
// The output format is: "sourcefile(linenumber)" or
|
||||||
// "modulename!address" or
|
// "modulename!address" or
|
||||||
// "address"
|
// "address"
|
||||||
static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo )
|
static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo )
|
||||||
{
|
{
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
IMAGEHLP_LINE lineInfo;
|
IMAGEHLP_LINE lineInfo;
|
||||||
DWORD dwDisp;
|
DWORD dwDisp;
|
||||||
TCHAR lpszFileName[BUFFERSIZE] = _T("");
|
TCHAR lpszFileName[BUFFERSIZE] = _T("");
|
||||||
TCHAR lpModuleInfo[BUFFERSIZE] = _T("");
|
TCHAR lpModuleInfo[BUFFERSIZE] = _T("");
|
||||||
|
|
||||||
_tcscpy( lpszSourceInfo, _T("?(?)") );
|
_tcscpy( lpszSourceInfo, _T("?(?)") );
|
||||||
|
|
||||||
::ZeroMemory( &lineInfo, sizeof( lineInfo ) );
|
::ZeroMemory( &lineInfo, sizeof( lineInfo ) );
|
||||||
lineInfo.SizeOfStruct = sizeof( lineInfo );
|
lineInfo.SizeOfStruct = sizeof( lineInfo );
|
||||||
|
|
||||||
if ( SymGetLineFromAddr( GetCurrentProcess(), address, &dwDisp, &lineInfo ) )
|
if ( SymGetLineFromAddr( GetCurrentProcess(), address, &dwDisp, &lineInfo ) )
|
||||||
{
|
{
|
||||||
// Got it. Let's use "sourcefile(linenumber)" format
|
// Got it. Let's use "sourcefile(linenumber)" format
|
||||||
PCSTR2LPTSTR( lineInfo.FileName, lpszFileName );
|
PCSTR2LPTSTR( lineInfo.FileName, lpszFileName );
|
||||||
TCHAR fname[_MAX_FNAME];
|
TCHAR fname[_MAX_FNAME];
|
||||||
TCHAR ext[_MAX_EXT];
|
TCHAR ext[_MAX_EXT];
|
||||||
_tsplitpath(lpszFileName, NULL, NULL, fname, ext);
|
_tsplitpath(lpszFileName, NULL, NULL, fname, ext);
|
||||||
_stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber );
|
_stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber );
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// There is no source file information. :(
|
// There is no source file information. :(
|
||||||
// Let's use the "modulename!address" format
|
// Let's use the "modulename!address" format
|
||||||
GetModuleNameFromAddress( address, lpModuleInfo );
|
GetModuleNameFromAddress( address, lpModuleInfo );
|
||||||
|
|
||||||
if ( lpModuleInfo[0] == _T('?') || lpModuleInfo[0] == _T('\0'))
|
if ( lpModuleInfo[0] == _T('?') || lpModuleInfo[0] == _T('\0'))
|
||||||
// There is no modulename information. :((
|
// There is no modulename information. :((
|
||||||
// Let's use the "address" format
|
// Let's use the "address" format
|
||||||
_stprintf( lpszSourceInfo, _T("0x%08X"), address );
|
_stprintf( lpszSourceInfo, _T("0x%08X"), address );
|
||||||
else
|
else
|
||||||
_stprintf( lpszSourceInfo, _T("%s!0x%08X"), lpModuleInfo, address );
|
_stprintf( lpszSourceInfo, _T("%s!0x%08X"), lpModuleInfo, address );
|
||||||
|
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
|
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
|
||||||
{
|
{
|
||||||
STACKFRAME callStack;
|
STACKFRAME callStack;
|
||||||
BOOL bResult;
|
BOOL bResult;
|
||||||
CONTEXT context;
|
CONTEXT context;
|
||||||
TCHAR symInfo[BUFFERSIZE] = _T("?");
|
TCHAR symInfo[BUFFERSIZE] = _T("?");
|
||||||
TCHAR srcInfo[BUFFERSIZE] = _T("?");
|
TCHAR srcInfo[BUFFERSIZE] = _T("?");
|
||||||
HANDLE hProcess = GetCurrentProcess();
|
HANDLE hProcess = GetCurrentProcess();
|
||||||
|
|
||||||
// If it's not this thread, let's suspend it, and resume it at the end
|
// If it's not this thread, let's suspend it, and resume it at the end
|
||||||
if ( hThread != GetCurrentThread() )
|
if ( hThread != GetCurrentThread() )
|
||||||
if ( SuspendThread( hThread ) == -1 )
|
if ( SuspendThread( hThread ) == -1 )
|
||||||
{
|
{
|
||||||
// whaaat ?!
|
// whaaat ?!
|
||||||
etfprint(file, "Call stack info failed\n");
|
etfprint(file, "Call stack info failed\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
::ZeroMemory( &context, sizeof(context) );
|
::ZeroMemory( &context, sizeof(context) );
|
||||||
context.ContextFlags = CONTEXT_FULL;
|
context.ContextFlags = CONTEXT_FULL;
|
||||||
|
|
||||||
if ( !GetThreadContext( hThread, &context ) )
|
if ( !GetThreadContext( hThread, &context ) )
|
||||||
{
|
{
|
||||||
etfprint(file, "Call stack info failed\n");
|
etfprint(file, "Call stack info failed\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
::ZeroMemory( &callStack, sizeof(callStack) );
|
::ZeroMemory( &callStack, sizeof(callStack) );
|
||||||
#ifndef _M_X64
|
#ifndef _M_X64
|
||||||
callStack.AddrPC.Offset = context.Eip;
|
callStack.AddrPC.Offset = context.Eip;
|
||||||
callStack.AddrStack.Offset = context.Esp;
|
callStack.AddrStack.Offset = context.Esp;
|
||||||
callStack.AddrFrame.Offset = context.Ebp;
|
callStack.AddrFrame.Offset = context.Ebp;
|
||||||
#else
|
#else
|
||||||
callStack.AddrPC.Offset = context.Rip;
|
callStack.AddrPC.Offset = context.Rip;
|
||||||
callStack.AddrStack.Offset = context.Rsp;
|
callStack.AddrStack.Offset = context.Rsp;
|
||||||
callStack.AddrFrame.Offset = context.Rbp;
|
callStack.AddrFrame.Offset = context.Rbp;
|
||||||
#endif
|
#endif
|
||||||
callStack.AddrPC.Mode = AddrModeFlat;
|
callStack.AddrPC.Mode = AddrModeFlat;
|
||||||
callStack.AddrStack.Mode = AddrModeFlat;
|
callStack.AddrStack.Mode = AddrModeFlat;
|
||||||
callStack.AddrFrame.Mode = AddrModeFlat;
|
callStack.AddrFrame.Mode = AddrModeFlat;
|
||||||
|
|
||||||
etfprint(file, "Call stack info: \n");
|
etfprint(file, "Call stack info: \n");
|
||||||
etfprint(file, lpszMessage);
|
etfprint(file, lpszMessage);
|
||||||
|
|
||||||
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
|
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
|
||||||
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
|
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
|
||||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||||
|
|
||||||
for( ULONG index = 0; ; index++ )
|
for( ULONG index = 0; ; index++ )
|
||||||
{
|
{
|
||||||
bResult = StackWalk(
|
bResult = StackWalk(
|
||||||
IMAGE_FILE_MACHINE_I386,
|
IMAGE_FILE_MACHINE_I386,
|
||||||
hProcess,
|
hProcess,
|
||||||
hThread,
|
hThread,
|
||||||
&callStack,
|
&callStack,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
SymFunctionTableAccess,
|
SymFunctionTableAccess,
|
||||||
SymGetModuleBase,
|
SymGetModuleBase,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if ( index == 0 )
|
if ( index == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( !bResult || callStack.AddrFrame.Offset == 0 )
|
if( !bResult || callStack.AddrFrame.Offset == 0 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
|
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
|
||||||
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
|
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
|
||||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( hThread != GetCurrentThread() )
|
if ( hThread != GetCurrentThread() )
|
||||||
ResumeThread( hThread );
|
ResumeThread( hThread );
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp )
|
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp )
|
||||||
{
|
{
|
||||||
STACKFRAME callStack;
|
STACKFRAME callStack;
|
||||||
BOOL bResult;
|
BOOL bResult;
|
||||||
TCHAR symInfo[BUFFERSIZE] = _T("?");
|
TCHAR symInfo[BUFFERSIZE] = _T("?");
|
||||||
TCHAR srcInfo[BUFFERSIZE] = _T("?");
|
TCHAR srcInfo[BUFFERSIZE] = _T("?");
|
||||||
HANDLE hProcess = GetCurrentProcess();
|
HANDLE hProcess = GetCurrentProcess();
|
||||||
|
|
||||||
// If it's not this thread, let's suspend it, and resume it at the end
|
// If it's not this thread, let's suspend it, and resume it at the end
|
||||||
if ( hThread != GetCurrentThread() )
|
if ( hThread != GetCurrentThread() )
|
||||||
if ( SuspendThread( hThread ) == -1 )
|
if ( SuspendThread( hThread ) == -1 )
|
||||||
{
|
{
|
||||||
// whaaat ?!
|
// whaaat ?!
|
||||||
etfprint(file, "Call stack info failed\n");
|
etfprint(file, "Call stack info failed\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
::ZeroMemory( &callStack, sizeof(callStack) );
|
::ZeroMemory( &callStack, sizeof(callStack) );
|
||||||
callStack.AddrPC.Offset = eip;
|
callStack.AddrPC.Offset = eip;
|
||||||
callStack.AddrStack.Offset = esp;
|
callStack.AddrStack.Offset = esp;
|
||||||
callStack.AddrFrame.Offset = ebp;
|
callStack.AddrFrame.Offset = ebp;
|
||||||
callStack.AddrPC.Mode = AddrModeFlat;
|
callStack.AddrPC.Mode = AddrModeFlat;
|
||||||
callStack.AddrStack.Mode = AddrModeFlat;
|
callStack.AddrStack.Mode = AddrModeFlat;
|
||||||
callStack.AddrFrame.Mode = AddrModeFlat;
|
callStack.AddrFrame.Mode = AddrModeFlat;
|
||||||
|
|
||||||
etfprint(file, "Call stack info: \n");
|
etfprint(file, "Call stack info: \n");
|
||||||
etfprint(file, lpszMessage);
|
etfprint(file, lpszMessage);
|
||||||
|
|
||||||
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
|
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
|
||||||
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
|
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
|
||||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||||
|
|
||||||
for( ULONG index = 0; ; index++ )
|
for( ULONG index = 0; ; index++ )
|
||||||
{
|
{
|
||||||
bResult = StackWalk(
|
bResult = StackWalk(
|
||||||
IMAGE_FILE_MACHINE_I386,
|
IMAGE_FILE_MACHINE_I386,
|
||||||
hProcess,
|
hProcess,
|
||||||
hThread,
|
hThread,
|
||||||
&callStack,
|
&callStack,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
SymFunctionTableAccess,
|
SymFunctionTableAccess,
|
||||||
SymGetModuleBase,
|
SymGetModuleBase,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if ( index == 0 )
|
if ( index == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( !bResult || callStack.AddrFrame.Offset == 0 )
|
if( !bResult || callStack.AddrFrame.Offset == 0 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
|
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
|
||||||
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
|
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
|
||||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( hThread != GetCurrentThread() )
|
if ( hThread != GetCurrentThread() )
|
||||||
ResumeThread( hThread );
|
ResumeThread( hThread );
|
||||||
}
|
}
|
||||||
|
|
||||||
char g_uefbuf[2048];
|
char g_uefbuf[2048];
|
||||||
|
|
||||||
void etfprintf(FILE *file, const char *format, ...) {
|
void etfprintf(FILE *file, const char *format, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
int len = vsprintf(g_uefbuf, format, ap);
|
int len = vsprintf(g_uefbuf, format, ap);
|
||||||
fwrite(g_uefbuf, 1, len, file);
|
fwrite(g_uefbuf, 1, len, file);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void etfprint(FILE *file, const std::string &text) {
|
void etfprint(FILE *file, const std::string &text) {
|
||||||
size_t len = text.length();
|
size_t len = text.length();
|
||||||
fwrite(text.data(), 1, len, file);
|
fwrite(text.data(), 1, len, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //WIN32
|
#endif //WIN32
|
||||||
|
|
|
@ -1,119 +1,119 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#else
|
#else
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "FileSearch.h"
|
#include "FileSearch.h"
|
||||||
|
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
|
|
||||||
|
|
||||||
CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, const CFileSearch::XStringVector& _rDirectories)
|
CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, const CFileSearch::XStringVector& _rDirectories)
|
||||||
{
|
{
|
||||||
// Reverse the loop order for speed?
|
// Reverse the loop order for speed?
|
||||||
for (size_t j = 0; j < _rSearchStrings.size(); j++)
|
for (size_t j = 0; j < _rSearchStrings.size(); j++)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < _rDirectories.size(); i++)
|
for (size_t i = 0; i < _rDirectories.size(); i++)
|
||||||
{
|
{
|
||||||
FindFiles(_rSearchStrings[j], _rDirectories[i]);
|
FindFiles(_rSearchStrings[j], _rDirectories[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath)
|
void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath)
|
||||||
{
|
{
|
||||||
std::string GCMSearchPath;
|
std::string GCMSearchPath;
|
||||||
BuildCompleteFilename(GCMSearchPath, _strPath, _searchString);
|
BuildCompleteFilename(GCMSearchPath, _strPath, _searchString);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WIN32_FIND_DATA findData;
|
WIN32_FIND_DATA findData;
|
||||||
HANDLE FindFirst = FindFirstFile(GCMSearchPath.c_str(), &findData);
|
HANDLE FindFirst = FindFirstFile(GCMSearchPath.c_str(), &findData);
|
||||||
|
|
||||||
if (FindFirst != INVALID_HANDLE_VALUE)
|
if (FindFirst != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
bool bkeepLooping = true;
|
bool bkeepLooping = true;
|
||||||
|
|
||||||
while (bkeepLooping)
|
while (bkeepLooping)
|
||||||
{
|
{
|
||||||
if (findData.cFileName[0] != '.')
|
if (findData.cFileName[0] != '.')
|
||||||
{
|
{
|
||||||
std::string strFilename;
|
std::string strFilename;
|
||||||
BuildCompleteFilename(strFilename, _strPath, findData.cFileName);
|
BuildCompleteFilename(strFilename, _strPath, findData.cFileName);
|
||||||
m_FileNames.push_back(strFilename);
|
m_FileNames.push_back(strFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
bkeepLooping = FindNextFile(FindFirst, &findData) ? true : false;
|
bkeepLooping = FindNextFile(FindFirst, &findData) ? true : false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FindClose(FindFirst);
|
FindClose(FindFirst);
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
size_t dot_pos = _searchString.rfind(".");
|
size_t dot_pos = _searchString.rfind(".");
|
||||||
|
|
||||||
if (dot_pos == std::string::npos)
|
if (dot_pos == std::string::npos)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ext = _searchString.substr(dot_pos);
|
std::string ext = _searchString.substr(dot_pos);
|
||||||
DIR* dir = opendir(_strPath.c_str());
|
DIR* dir = opendir(_strPath.c_str());
|
||||||
|
|
||||||
if (!dir)
|
if (!dir)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dirent* dp;
|
dirent* dp;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
dp = readdir(dir);
|
dp = readdir(dir);
|
||||||
|
|
||||||
if (!dp)
|
if (!dp)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string s(dp->d_name);
|
std::string s(dp->d_name);
|
||||||
|
|
||||||
if ( (s.size() > ext.size()) && (!strcasecmp(s.substr(s.size() - ext.size()).c_str(), ext.c_str())) )
|
if ( (s.size() > ext.size()) && (!strcasecmp(s.substr(s.size() - ext.size()).c_str(), ext.c_str())) )
|
||||||
{
|
{
|
||||||
std::string full_name = _strPath + "/" + s;
|
std::string full_name = _strPath + "/" + s;
|
||||||
m_FileNames.push_back(full_name);
|
m_FileNames.push_back(full_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const CFileSearch::XStringVector& CFileSearch::GetFileNames() const
|
const CFileSearch::XStringVector& CFileSearch::GetFileNames() const
|
||||||
{
|
{
|
||||||
return(m_FileNames);
|
return(m_FileNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,496 +1,496 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "FileUtil.h"
|
#include "FileUtil.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <shlobj.h> // for SHGetFolderPath
|
#include <shlobj.h> // for SHGetFolderPath
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#include <commdlg.h> // for GetSaveFileName
|
#include <commdlg.h> // for GetSaveFileName
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <direct.h> // getcwd
|
#include <direct.h> // getcwd
|
||||||
#else
|
#else
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#ifndef S_ISDIR
|
#ifndef S_ISDIR
|
||||||
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
|
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace File
|
namespace File
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// Remove any ending forward slashes from directory paths
|
// Remove any ending forward slashes from directory paths
|
||||||
// -------------
|
// -------------
|
||||||
inline void StripTailDirSlashes(std::string& fname)
|
inline void StripTailDirSlashes(std::string& fname)
|
||||||
{
|
{
|
||||||
// Make sure it's not a blank string
|
// Make sure it's not a blank string
|
||||||
if(fname.length() > 0)
|
if(fname.length() > 0)
|
||||||
{
|
{
|
||||||
while(fname.at(fname.length() - 1) == DIR_SEP_CHR)
|
while(fname.at(fname.length() - 1) == DIR_SEP_CHR)
|
||||||
fname.resize(fname.length() - 1);
|
fname.resize(fname.length() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// =============
|
// =============
|
||||||
|
|
||||||
|
|
||||||
bool Exists(const char *filename)
|
bool Exists(const char *filename)
|
||||||
{
|
{
|
||||||
struct stat file_info;
|
struct stat file_info;
|
||||||
|
|
||||||
std::string copy = filename;
|
std::string copy = filename;
|
||||||
StripTailDirSlashes(copy);
|
StripTailDirSlashes(copy);
|
||||||
|
|
||||||
int result = stat(copy.c_str(), &file_info);
|
int result = stat(copy.c_str(), &file_info);
|
||||||
return (result == 0);
|
return (result == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsDirectory(const char *filename)
|
bool IsDirectory(const char *filename)
|
||||||
{
|
{
|
||||||
struct stat file_info;
|
struct stat file_info;
|
||||||
std::string copy = filename;
|
std::string copy = filename;
|
||||||
StripTailDirSlashes(copy);
|
StripTailDirSlashes(copy);
|
||||||
|
|
||||||
int result = stat(copy.c_str(), &file_info);
|
int result = stat(copy.c_str(), &file_info);
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
return S_ISDIR(file_info.st_mode);
|
return S_ISDIR(file_info.st_mode);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Delete(const char *filename)
|
bool Delete(const char *filename)
|
||||||
{
|
{
|
||||||
if (!Exists(filename))
|
if (!Exists(filename))
|
||||||
return false;
|
return false;
|
||||||
if (IsDirectory(filename))
|
if (IsDirectory(filename))
|
||||||
return false;
|
return false;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DeleteFile(filename);
|
DeleteFile(filename);
|
||||||
#else
|
#else
|
||||||
unlink(filename);
|
unlink(filename);
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SanitizePath(const char *filename)
|
std::string SanitizePath(const char *filename)
|
||||||
{
|
{
|
||||||
|
|
||||||
std::string copy = filename;
|
std::string copy = filename;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
for (size_t i = 0; i < copy.size(); i++)
|
for (size_t i = 0; i < copy.size(); i++)
|
||||||
if (copy[i] == '/')
|
if (copy[i] == '/')
|
||||||
copy[i] = '\\';
|
copy[i] = '\\';
|
||||||
#else
|
#else
|
||||||
// Should we do the otherway around?
|
// Should we do the otherway around?
|
||||||
#endif
|
#endif
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launch(const char *filename)
|
void Launch(const char *filename)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::string win_filename = SanitizePath(filename);
|
std::string win_filename = SanitizePath(filename);
|
||||||
SHELLEXECUTEINFO shex = { sizeof(shex) };
|
SHELLEXECUTEINFO shex = { sizeof(shex) };
|
||||||
shex.fMask = SEE_MASK_NO_CONSOLE; // | SEE_MASK_ASYNC_OK;
|
shex.fMask = SEE_MASK_NO_CONSOLE; // | SEE_MASK_ASYNC_OK;
|
||||||
shex.lpVerb = "open";
|
shex.lpVerb = "open";
|
||||||
shex.lpFile = win_filename.c_str();
|
shex.lpFile = win_filename.c_str();
|
||||||
shex.nShow = SW_SHOWNORMAL;
|
shex.nShow = SW_SHOWNORMAL;
|
||||||
ShellExecuteEx(&shex);
|
ShellExecuteEx(&shex);
|
||||||
#else
|
#else
|
||||||
// TODO: Insert GNOME/KDE code here.
|
// TODO: Insert GNOME/KDE code here.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Explore(const char *path)
|
void Explore(const char *path)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::string win_path = SanitizePath(path);
|
std::string win_path = SanitizePath(path);
|
||||||
SHELLEXECUTEINFO shex = { sizeof(shex) };
|
SHELLEXECUTEINFO shex = { sizeof(shex) };
|
||||||
shex.fMask = SEE_MASK_NO_CONSOLE; // | SEE_MASK_ASYNC_OK;
|
shex.fMask = SEE_MASK_NO_CONSOLE; // | SEE_MASK_ASYNC_OK;
|
||||||
shex.lpVerb = "explore";
|
shex.lpVerb = "explore";
|
||||||
shex.lpFile = win_path.c_str();
|
shex.lpFile = win_path.c_str();
|
||||||
shex.nShow = SW_SHOWNORMAL;
|
shex.nShow = SW_SHOWNORMAL;
|
||||||
ShellExecuteEx(&shex);
|
ShellExecuteEx(&shex);
|
||||||
#else
|
#else
|
||||||
// TODO: Insert GNOME/KDE code here.
|
// TODO: Insert GNOME/KDE code here.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if successful, or path already exists.
|
// Returns true if successful, or path already exists.
|
||||||
bool CreateDir(const char *path)
|
bool CreateDir(const char *path)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (::CreateDirectory(path, NULL))
|
if (::CreateDirectory(path, NULL))
|
||||||
return true;
|
return true;
|
||||||
DWORD error = GetLastError();
|
DWORD error = GetLastError();
|
||||||
if (error == ERROR_ALREADY_EXISTS)
|
if (error == ERROR_ALREADY_EXISTS)
|
||||||
{
|
{
|
||||||
PanicAlert("%s already exists", path);
|
PanicAlert("%s already exists", path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
PanicAlert("Error creating directory %s: %i", path, error);
|
PanicAlert("Error creating directory %s: %i", path, error);
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
if (mkdir(path, 0755) == 0)
|
if (mkdir(path, 0755) == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
|
||||||
if (err == EEXIST)
|
if (err == EEXIST)
|
||||||
{
|
{
|
||||||
PanicAlert("%s already exists", path);
|
PanicAlert("%s already exists", path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PanicAlert("Error creating directory %s: %s", path, strerror(err));
|
PanicAlert("Error creating directory %s: %s", path, strerror(err));
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create several dirs
|
// Create several dirs
|
||||||
bool CreateDirectoryStructure(const std::string& _rFullPath)
|
bool CreateDirectoryStructure(const std::string& _rFullPath)
|
||||||
{
|
{
|
||||||
int PanicCounter = 10;
|
int PanicCounter = 10;
|
||||||
|
|
||||||
size_t Position = 0;
|
size_t Position = 0;
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
// Find next sub path, support both \ and / directory separators
|
// Find next sub path, support both \ and / directory separators
|
||||||
{
|
{
|
||||||
size_t nextPosition = _rFullPath.find(DIR_SEP_CHR, Position);
|
size_t nextPosition = _rFullPath.find(DIR_SEP_CHR, Position);
|
||||||
Position = nextPosition;
|
Position = nextPosition;
|
||||||
|
|
||||||
if (Position == std::string::npos)
|
if (Position == std::string::npos)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Position++;
|
Position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create next sub path
|
// Create next sub path
|
||||||
std::string SubPath = _rFullPath.substr(0, Position);
|
std::string SubPath = _rFullPath.substr(0, Position);
|
||||||
if (!SubPath.empty())
|
if (!SubPath.empty())
|
||||||
{
|
{
|
||||||
if (!File::IsDirectory(SubPath.c_str()))
|
if (!File::IsDirectory(SubPath.c_str()))
|
||||||
{
|
{
|
||||||
File::CreateDir(SubPath.c_str());
|
File::CreateDir(SubPath.c_str());
|
||||||
LOG(WII_IPC_FILEIO, " CreateSubDir %s", SubPath.c_str());
|
LOG(WII_IPC_FILEIO, " CreateSubDir %s", SubPath.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A safety check
|
// A safety check
|
||||||
PanicCounter--;
|
PanicCounter--;
|
||||||
if (PanicCounter <= 0)
|
if (PanicCounter <= 0)
|
||||||
{
|
{
|
||||||
PanicAlert("CreateDirectoryStruct creates way to much dirs...");
|
PanicAlert("CreateDirectoryStruct creates way to much dirs...");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DeleteDir(const char *filename)
|
bool DeleteDir(const char *filename)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!File::IsDirectory(filename))
|
if (!File::IsDirectory(filename))
|
||||||
return false;
|
return false;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return ::RemoveDirectory (filename) ? true : false;
|
return ::RemoveDirectory (filename) ? true : false;
|
||||||
#else
|
#else
|
||||||
if (rmdir(filename) == 0)
|
if (rmdir(filename) == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
|
||||||
PanicAlert("Error removing directory %s",strerror(err));
|
PanicAlert("Error removing directory %s",strerror(err));
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Rename(const char *srcFilename, const char *destFilename)
|
bool Rename(const char *srcFilename, const char *destFilename)
|
||||||
{
|
{
|
||||||
return (rename(srcFilename, destFilename) == 0);
|
return (rename(srcFilename, destFilename) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Copy(const char *srcFilename, const char *destFilename)
|
bool Copy(const char *srcFilename, const char *destFilename)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return (CopyFile(srcFilename, destFilename, FALSE) == TRUE) ? true : false;
|
return (CopyFile(srcFilename, destFilename, FALSE) == TRUE) ? true : false;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define BSIZE 1024
|
#define BSIZE 1024
|
||||||
|
|
||||||
int rnum, wnum, err;
|
int rnum, wnum, err;
|
||||||
char buffer[BSIZE];
|
char buffer[BSIZE];
|
||||||
FILE *output, *input;
|
FILE *output, *input;
|
||||||
|
|
||||||
if (! (input = fopen(srcFilename, "r"))) {
|
if (! (input = fopen(srcFilename, "r"))) {
|
||||||
err = errno;
|
err = errno;
|
||||||
PanicAlert("Error copying from %s: %s", srcFilename, strerror(err));
|
PanicAlert("Error copying from %s: %s", srcFilename, strerror(err));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! (output = fopen(destFilename, "w"))) {
|
if (! (output = fopen(destFilename, "w"))) {
|
||||||
err = errno;
|
err = errno;
|
||||||
PanicAlert("Error copying to %s: %s", destFilename, strerror(err));
|
PanicAlert("Error copying to %s: %s", destFilename, strerror(err));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(! feof(input)) {
|
while(! feof(input)) {
|
||||||
if((rnum = fread(buffer, sizeof(char), BSIZE, input)) != BSIZE) {
|
if((rnum = fread(buffer, sizeof(char), BSIZE, input)) != BSIZE) {
|
||||||
if(ferror(input) != 0){
|
if(ferror(input) != 0){
|
||||||
PanicAlert("can't read source file\n");
|
PanicAlert("can't read source file\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if((wnum = fwrite(buffer, sizeof(char), rnum, output))!= rnum){
|
if((wnum = fwrite(buffer, sizeof(char), rnum, output))!= rnum){
|
||||||
PanicAlert("can't write output file\n");
|
PanicAlert("can't write output file\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(input);
|
fclose(input);
|
||||||
fclose(output);
|
fclose(output);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
/*
|
/*
|
||||||
std::ifstream ifs(srcFilename, std::ios::binary);
|
std::ifstream ifs(srcFilename, std::ios::binary);
|
||||||
std::ofstream ofs(destFilename, std::ios::binary);
|
std::ofstream ofs(destFilename, std::ios::binary);
|
||||||
|
|
||||||
ofs << ifs.rdbuf();
|
ofs << ifs.rdbuf();
|
||||||
|
|
||||||
ifs.close();
|
ifs.close();
|
||||||
ofs.close();
|
ofs.close();
|
||||||
|
|
||||||
return true;*/
|
return true;*/
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetUserDirectory()
|
std::string GetUserDirectory()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
char path[MAX_PATH];
|
char path[MAX_PATH];
|
||||||
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, path)))
|
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, path)))
|
||||||
{
|
{
|
||||||
return std::string(path);
|
return std::string(path);
|
||||||
}
|
}
|
||||||
return std::string("");
|
return std::string("");
|
||||||
#else
|
#else
|
||||||
char *dir = getenv("HOME");
|
char *dir = getenv("HOME");
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return std::string("");
|
return std::string("");
|
||||||
return dir;
|
return dir;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetSize(const char *filename)
|
u64 GetSize(const char *filename)
|
||||||
{
|
{
|
||||||
if(!Exists(filename))
|
if(!Exists(filename))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
if (stat(filename, &buf) == 0) {
|
if (stat(filename, &buf) == 0) {
|
||||||
return buf.st_size;
|
return buf.st_size;
|
||||||
}
|
}
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
|
||||||
PanicAlert("Error accessing %s: %s", filename, strerror(err));
|
PanicAlert("Error accessing %s: %s", filename, strerror(err));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static bool ReadFoundFile(const WIN32_FIND_DATA& ffd, FSTEntry& entry)
|
static bool ReadFoundFile(const WIN32_FIND_DATA& ffd, FSTEntry& entry)
|
||||||
{
|
{
|
||||||
// ignore files starting with a .
|
// ignore files starting with a .
|
||||||
if(strncmp(ffd.cFileName, ".", 1) == 0)
|
if(strncmp(ffd.cFileName, ".", 1) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
entry.virtualName = ffd.cFileName;
|
entry.virtualName = ffd.cFileName;
|
||||||
|
|
||||||
if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
{
|
{
|
||||||
entry.isDirectory = true;
|
entry.isDirectory = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
entry.isDirectory = false;
|
entry.isDirectory = false;
|
||||||
entry.size = ffd.nFileSizeLow;
|
entry.size = ffd.nFileSizeLow;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ScanDirectoryTree(const std::string& _Directory, FSTEntry& parentEntry)
|
u32 ScanDirectoryTree(const std::string& _Directory, FSTEntry& parentEntry)
|
||||||
{
|
{
|
||||||
// Find the first file in the directory.
|
// Find the first file in the directory.
|
||||||
WIN32_FIND_DATA ffd;
|
WIN32_FIND_DATA ffd;
|
||||||
std::string searchName = _Directory + "\\*";
|
std::string searchName = _Directory + "\\*";
|
||||||
HANDLE hFind = FindFirstFile(searchName.c_str(), &ffd);
|
HANDLE hFind = FindFirstFile(searchName.c_str(), &ffd);
|
||||||
|
|
||||||
u32 foundEntries = 0;
|
u32 foundEntries = 0;
|
||||||
|
|
||||||
if (hFind != INVALID_HANDLE_VALUE)
|
if (hFind != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
FSTEntry entry;
|
FSTEntry entry;
|
||||||
|
|
||||||
if(ReadFoundFile(ffd, entry))
|
if(ReadFoundFile(ffd, entry))
|
||||||
{
|
{
|
||||||
entry.physicalName = _Directory + "\\" + entry.virtualName;
|
entry.physicalName = _Directory + "\\" + entry.virtualName;
|
||||||
if(entry.isDirectory)
|
if(entry.isDirectory)
|
||||||
{
|
{
|
||||||
u32 childEntries = ScanDirectoryTree(entry.physicalName, entry);
|
u32 childEntries = ScanDirectoryTree(entry.physicalName, entry);
|
||||||
entry.size = childEntries;
|
entry.size = childEntries;
|
||||||
foundEntries += childEntries;
|
foundEntries += childEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
++foundEntries;
|
++foundEntries;
|
||||||
|
|
||||||
parentEntry.children.push_back(entry);
|
parentEntry.children.push_back(entry);
|
||||||
}
|
}
|
||||||
} while (FindNextFile(hFind, &ffd) != 0);
|
} while (FindNextFile(hFind, &ffd) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FindClose(hFind);
|
FindClose(hFind);
|
||||||
|
|
||||||
return foundEntries;
|
return foundEntries;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
u32 ScanDirectoryTree(const std::string& _Directory, FSTEntry& parentEntry)
|
u32 ScanDirectoryTree(const std::string& _Directory, FSTEntry& parentEntry)
|
||||||
{
|
{
|
||||||
PanicAlert("Scan directory not implemanted yet\n");
|
PanicAlert("Scan directory not implemanted yet\n");
|
||||||
// TODO - Insert linux stuff here
|
// TODO - Insert linux stuff here
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool CreateEmptyFile(const char *filename)
|
bool CreateEmptyFile(const char *filename)
|
||||||
{
|
{
|
||||||
FILE* pFile = fopen(filename, "wb");
|
FILE* pFile = fopen(filename, "wb");
|
||||||
if (pFile == NULL)
|
if (pFile == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DeleteDirRecursively(const std::string& _Directory)
|
bool DeleteDirRecursively(const std::string& _Directory)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
bool Result = false;
|
bool Result = false;
|
||||||
|
|
||||||
WIN32_FIND_DATA ffd;
|
WIN32_FIND_DATA ffd;
|
||||||
std::string searchName = _Directory + "\\*";
|
std::string searchName = _Directory + "\\*";
|
||||||
HANDLE hFind = FindFirstFile(searchName.c_str(), &ffd);
|
HANDLE hFind = FindFirstFile(searchName.c_str(), &ffd);
|
||||||
|
|
||||||
if (hFind != INVALID_HANDLE_VALUE)
|
if (hFind != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// check for "." and ".."
|
// check for "." and ".."
|
||||||
if (((ffd.cFileName[0] == '.') && (ffd.cFileName[1] == 0x00)) ||
|
if (((ffd.cFileName[0] == '.') && (ffd.cFileName[1] == 0x00)) ||
|
||||||
((ffd.cFileName[0] == '.') && (ffd.cFileName[1] == '.') && (ffd.cFileName[2] == 0x00)))
|
((ffd.cFileName[0] == '.') && (ffd.cFileName[1] == '.') && (ffd.cFileName[2] == 0x00)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// build path
|
// build path
|
||||||
std::string newPath(_Directory);
|
std::string newPath(_Directory);
|
||||||
newPath += '\\';
|
newPath += '\\';
|
||||||
newPath += ffd.cFileName;
|
newPath += ffd.cFileName;
|
||||||
|
|
||||||
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
{
|
{
|
||||||
if (!File::DeleteDirRecursively(newPath))
|
if (!File::DeleteDirRecursively(newPath))
|
||||||
goto error_jmp;
|
goto error_jmp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!File::Delete(newPath.c_str()))
|
if (!File::Delete(newPath.c_str()))
|
||||||
goto error_jmp;
|
goto error_jmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (FindNextFile(hFind, &ffd) != 0);
|
} while (FindNextFile(hFind, &ffd) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!File::DeleteDir(_Directory.c_str()))
|
if (!File::DeleteDir(_Directory.c_str()))
|
||||||
goto error_jmp;
|
goto error_jmp;
|
||||||
|
|
||||||
Result = true;
|
Result = true;
|
||||||
|
|
||||||
error_jmp:
|
error_jmp:
|
||||||
|
|
||||||
FindClose(hFind);
|
FindClose(hFind);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
#else
|
#else
|
||||||
// taken from http://www.dreamincode.net/code/snippet2700.htm
|
// taken from http://www.dreamincode.net/code/snippet2700.htm
|
||||||
DIR *pdir = NULL;
|
DIR *pdir = NULL;
|
||||||
pdir = opendir (_Directory.c_str());
|
pdir = opendir (_Directory.c_str());
|
||||||
struct dirent *pent = NULL;
|
struct dirent *pent = NULL;
|
||||||
|
|
||||||
if (pdir == NULL) {
|
if (pdir == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char file[256];
|
char file[256];
|
||||||
|
|
||||||
int counter = 1;
|
int counter = 1;
|
||||||
|
|
||||||
while ((pent = readdir(pdir))) {
|
while ((pent = readdir(pdir))) {
|
||||||
if (counter > 2) {
|
if (counter > 2) {
|
||||||
for (int i = 0; i < 256; i++) file[i] = '\0';
|
for (int i = 0; i < 256; i++) file[i] = '\0';
|
||||||
strcat(file, _Directory.c_str());
|
strcat(file, _Directory.c_str());
|
||||||
if (pent == NULL) {
|
if (pent == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
strcat(file, pent->d_name);
|
strcat(file, pent->d_name);
|
||||||
if (IsDirectory(file) == true) {
|
if (IsDirectory(file) == true) {
|
||||||
DeleteDir(file);
|
DeleteDir(file);
|
||||||
} else {
|
} else {
|
||||||
remove(file);
|
remove(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return DeleteDir(_Directory.c_str());
|
return DeleteDir(_Directory.c_str());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetCurrentDirectory(std::string& _rDirectory)
|
void GetCurrentDirectory(std::string& _rDirectory)
|
||||||
{
|
{
|
||||||
char tmpBuffer[MAX_PATH+1];
|
char tmpBuffer[MAX_PATH+1];
|
||||||
getcwd(tmpBuffer, MAX_PATH);
|
getcwd(tmpBuffer, MAX_PATH);
|
||||||
_rDirectory = tmpBuffer;
|
_rDirectory = tmpBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,136 +1,136 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Hash.h"
|
#include "Hash.h"
|
||||||
|
|
||||||
// uint32_t
|
// uint32_t
|
||||||
// WARNING - may read one more byte!
|
// WARNING - may read one more byte!
|
||||||
// Implementation from Wikipedia.
|
// Implementation from Wikipedia.
|
||||||
u32 HashFletcher(const u8* data_u8, size_t length)
|
u32 HashFletcher(const u8* data_u8, size_t length)
|
||||||
{
|
{
|
||||||
const u16* data = (const u16*)data_u8; /* Pointer to the data to be summed */
|
const u16* data = (const u16*)data_u8; /* Pointer to the data to be summed */
|
||||||
size_t len = (length + 1) / 2; /* Length in 16-bit words */
|
size_t len = (length + 1) / 2; /* Length in 16-bit words */
|
||||||
u32 sum1 = 0xffff, sum2 = 0xffff;
|
u32 sum1 = 0xffff, sum2 = 0xffff;
|
||||||
|
|
||||||
while (len)
|
while (len)
|
||||||
{
|
{
|
||||||
size_t tlen = len > 360 ? 360 : len;
|
size_t tlen = len > 360 ? 360 : len;
|
||||||
len -= tlen;
|
len -= tlen;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
sum1 += *data++;
|
sum1 += *data++;
|
||||||
sum2 += sum1;
|
sum2 += sum1;
|
||||||
}
|
}
|
||||||
while (--tlen);
|
while (--tlen);
|
||||||
|
|
||||||
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
|
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
|
||||||
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
|
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Second reduction step to reduce sums to 16 bits */
|
/* Second reduction step to reduce sums to 16 bits */
|
||||||
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
|
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
|
||||||
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
|
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
|
||||||
return(sum2 << 16 | sum1);
|
return(sum2 << 16 | sum1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Implementation from Wikipedia
|
// Implementation from Wikipedia
|
||||||
// Slightly slower than Fletcher above, but slighly more reliable.
|
// Slightly slower than Fletcher above, but slighly more reliable.
|
||||||
#define MOD_ADLER 65521
|
#define MOD_ADLER 65521
|
||||||
// data: Pointer to the data to be summed; len is in bytes
|
// data: Pointer to the data to be summed; len is in bytes
|
||||||
u32 HashAdler32(const u8* data, size_t len)
|
u32 HashAdler32(const u8* data, size_t len)
|
||||||
{
|
{
|
||||||
u32 a = 1, b = 0;
|
u32 a = 1, b = 0;
|
||||||
|
|
||||||
while (len)
|
while (len)
|
||||||
{
|
{
|
||||||
size_t tlen = len > 5550 ? 5550 : len;
|
size_t tlen = len > 5550 ? 5550 : len;
|
||||||
len -= tlen;
|
len -= tlen;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
a += *data++;
|
a += *data++;
|
||||||
b += a;
|
b += a;
|
||||||
}
|
}
|
||||||
while (--tlen);
|
while (--tlen);
|
||||||
|
|
||||||
a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER);
|
a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER);
|
||||||
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
|
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
|
||||||
}
|
}
|
||||||
|
|
||||||
// It can be shown that a <= 0x1013a here, so a single subtract will do.
|
// It can be shown that a <= 0x1013a here, so a single subtract will do.
|
||||||
if (a >= MOD_ADLER)
|
if (a >= MOD_ADLER)
|
||||||
{
|
{
|
||||||
a -= MOD_ADLER;
|
a -= MOD_ADLER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It can be shown that b can reach 0xfff87 here.
|
// It can be shown that b can reach 0xfff87 here.
|
||||||
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
|
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
|
||||||
|
|
||||||
if (b >= MOD_ADLER)
|
if (b >= MOD_ADLER)
|
||||||
{
|
{
|
||||||
b -= MOD_ADLER;
|
b -= MOD_ADLER;
|
||||||
}
|
}
|
||||||
|
|
||||||
return((b << 16) | a);
|
return((b << 16) | a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Another fast and decent hash
|
// Another fast and decent hash
|
||||||
u32 HashFNV(const u8* ptr, int length)
|
u32 HashFNV(const u8* ptr, int length)
|
||||||
{
|
{
|
||||||
u32 hash = 0x811c9dc5;
|
u32 hash = 0x811c9dc5;
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
hash *= 1677761;
|
hash *= 1677761;
|
||||||
hash ^= ptr[i];
|
hash ^= ptr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return(hash);
|
return(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Another fast and decent hash
|
// Another fast and decent hash
|
||||||
u32 HashFNV1(const u8* ptr, int length)
|
u32 HashFNV1(const u8* ptr, int length)
|
||||||
{
|
{
|
||||||
u32 hash = 0x811c9dc5;
|
u32 hash = 0x811c9dc5;
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
hash *= 1677761;
|
hash *= 1677761;
|
||||||
hash ^= ptr[i];
|
hash ^= ptr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return(hash);
|
return(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Stupid hash - but can't go back now :)
|
// Stupid hash - but can't go back now :)
|
||||||
// Don't use for new things. At least it's reasonably fast.
|
// Don't use for new things. At least it's reasonably fast.
|
||||||
u32 HashEctor(const u8* ptr, int length)
|
u32 HashEctor(const u8* ptr, int length)
|
||||||
{
|
{
|
||||||
u32 crc = 0;
|
u32 crc = 0;
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
crc ^= ptr[i];
|
crc ^= ptr[i];
|
||||||
crc = (crc << 3) | (crc >> 29);
|
crc = (crc << 3) | (crc >> 29);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(crc);
|
return(crc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,469 +1,469 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
// see IniFile.h
|
// see IniFile.h
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "IniFile.h"
|
#include "IniFile.h"
|
||||||
|
|
||||||
IniFile::IniFile()
|
IniFile::IniFile()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
IniFile::~IniFile()
|
IniFile::~IniFile()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
Section::Section()
|
Section::Section()
|
||||||
: lines(), name(""), comment("") {}
|
: lines(), name(""), comment("") {}
|
||||||
|
|
||||||
|
|
||||||
Section::Section(const std::string& _name)
|
Section::Section(const std::string& _name)
|
||||||
: lines(), name(_name), comment("") {}
|
: lines(), name(_name), comment("") {}
|
||||||
|
|
||||||
|
|
||||||
Section::Section(const Section& other)
|
Section::Section(const Section& other)
|
||||||
{
|
{
|
||||||
name = other.name;
|
name = other.name;
|
||||||
comment = other.comment;
|
comment = other.comment;
|
||||||
lines = other.lines;
|
lines = other.lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Section* IniFile::GetSection(const char* sectionName) const
|
const Section* IniFile::GetSection(const char* sectionName) const
|
||||||
{
|
{
|
||||||
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
||||||
if (!strcmp(iter->name.c_str(), sectionName))
|
if (!strcmp(iter->name.c_str(), sectionName))
|
||||||
return (&(*iter));
|
return (&(*iter));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Section* IniFile::GetSection(const char* sectionName)
|
Section* IniFile::GetSection(const char* sectionName)
|
||||||
{
|
{
|
||||||
for (std::vector<Section>::iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
for (std::vector<Section>::iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
||||||
if (!strcmp(iter->name.c_str(), sectionName))
|
if (!strcmp(iter->name.c_str(), sectionName))
|
||||||
return (&(*iter));
|
return (&(*iter));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Section* IniFile::GetOrCreateSection(const char* sectionName)
|
Section* IniFile::GetOrCreateSection(const char* sectionName)
|
||||||
{
|
{
|
||||||
Section* section = GetSection(sectionName);
|
Section* section = GetSection(sectionName);
|
||||||
|
|
||||||
if (!section)
|
if (!section)
|
||||||
{
|
{
|
||||||
sections.push_back(Section(sectionName));
|
sections.push_back(Section(sectionName));
|
||||||
section = §ions[sections.size() - 1];
|
section = §ions[sections.size() - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return(section);
|
return(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IniFile::DeleteSection(const char* sectionName)
|
bool IniFile::DeleteSection(const char* sectionName)
|
||||||
{
|
{
|
||||||
Section* s = GetSection(sectionName);
|
Section* s = GetSection(sectionName);
|
||||||
|
|
||||||
if (!s)
|
if (!s)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<Section>::iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
for (std::vector<Section>::iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (&(*iter) == s)
|
if (&(*iter) == s)
|
||||||
{
|
{
|
||||||
sections.erase(iter);
|
sections.erase(iter);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IniFile::ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) const
|
void IniFile::ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) const
|
||||||
{
|
{
|
||||||
// allow many types of commenting
|
// allow many types of commenting
|
||||||
// These MUST be signed! Do not change to size_t
|
// These MUST be signed! Do not change to size_t
|
||||||
int firstEquals = (int)line.find("=", 0);
|
int firstEquals = (int)line.find("=", 0);
|
||||||
int firstCommentChar = (int)line.find(";", 0);
|
int firstCommentChar = (int)line.find(";", 0);
|
||||||
|
|
||||||
if (firstCommentChar < 0){firstCommentChar = (int)line.find("#", firstEquals > 0 ? firstEquals : 0);}
|
if (firstCommentChar < 0){firstCommentChar = (int)line.find("#", firstEquals > 0 ? firstEquals : 0);}
|
||||||
|
|
||||||
if (firstCommentChar < 0){firstCommentChar = (int)line.find("//", firstEquals > 0 ? firstEquals : 0);}
|
if (firstCommentChar < 0){firstCommentChar = (int)line.find("//", firstEquals > 0 ? firstEquals : 0);}
|
||||||
|
|
||||||
// allow preserval of spacing before comment
|
// allow preserval of spacing before comment
|
||||||
if (firstCommentChar > 0)
|
if (firstCommentChar > 0)
|
||||||
{
|
{
|
||||||
while (line[firstCommentChar - 1] == ' ' || line[firstCommentChar - 1] == 9) // 9 == tab
|
while (line[firstCommentChar - 1] == ' ' || line[firstCommentChar - 1] == 9) // 9 == tab
|
||||||
{
|
{
|
||||||
firstCommentChar--;
|
firstCommentChar--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((firstEquals >= 0) && ((firstCommentChar < 0) || (firstEquals < firstCommentChar)))
|
if ((firstEquals >= 0) && ((firstCommentChar < 0) || (firstEquals < firstCommentChar)))
|
||||||
{
|
{
|
||||||
// Yes, a valid line!
|
// Yes, a valid line!
|
||||||
*keyOut = StripSpaces(line.substr(0, firstEquals));
|
*keyOut = StripSpaces(line.substr(0, firstEquals));
|
||||||
|
|
||||||
if (commentOut)
|
if (commentOut)
|
||||||
{
|
{
|
||||||
*commentOut = firstCommentChar > 0 ? line.substr(firstCommentChar) : std::string("");
|
*commentOut = firstCommentChar > 0 ? line.substr(firstCommentChar) : std::string("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valueOut)
|
if (valueOut)
|
||||||
{
|
{
|
||||||
*valueOut = StripQuotes(StripSpaces(line.substr(firstEquals + 1, firstCommentChar - firstEquals - 1)));
|
*valueOut = StripQuotes(StripSpaces(line.substr(firstEquals + 1, firstCommentChar - firstEquals - 1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string* IniFile::GetLine(Section* section, const char* key, std::string* valueOut, std::string* commentOut)
|
std::string* IniFile::GetLine(Section* section, const char* key, std::string* valueOut, std::string* commentOut)
|
||||||
{
|
{
|
||||||
for (std::vector<std::string>::iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
|
for (std::vector<std::string>::iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
|
||||||
{
|
{
|
||||||
std::string& line = *iter;
|
std::string& line = *iter;
|
||||||
std::string lineKey;
|
std::string lineKey;
|
||||||
ParseLine(line, &lineKey, valueOut, commentOut);
|
ParseLine(line, &lineKey, valueOut, commentOut);
|
||||||
|
|
||||||
if (!stricmp(lineKey.c_str(), key))
|
if (!stricmp(lineKey.c_str(), key))
|
||||||
{
|
{
|
||||||
return &line;
|
return &line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IniFile::Set(const char* sectionName, const char* key, const char* newValue)
|
void IniFile::Set(const char* sectionName, const char* key, const char* newValue)
|
||||||
{
|
{
|
||||||
Section* section = GetOrCreateSection(sectionName);
|
Section* section = GetOrCreateSection(sectionName);
|
||||||
std::string value, comment;
|
std::string value, comment;
|
||||||
std::string* line = GetLine(section, key, &value, &comment);
|
std::string* line = GetLine(section, key, &value, &comment);
|
||||||
|
|
||||||
if (line)
|
if (line)
|
||||||
{
|
{
|
||||||
// Change the value - keep the key and comment
|
// Change the value - keep the key and comment
|
||||||
*line = StripSpaces(key) + " = " + newValue + comment;
|
*line = StripSpaces(key) + " = " + newValue + comment;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The key did not already exist in this section - let's add it.
|
// The key did not already exist in this section - let's add it.
|
||||||
section->lines.push_back(std::string(key) + " = " + newValue);
|
section->lines.push_back(std::string(key) + " = " + newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IniFile::Set(const char* sectionName, const char* key, u32 newValue)
|
void IniFile::Set(const char* sectionName, const char* key, u32 newValue)
|
||||||
{
|
{
|
||||||
Set(sectionName, key, StringFromFormat("0x%08x", newValue).c_str());
|
Set(sectionName, key, StringFromFormat("0x%08x", newValue).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IniFile::Set(const char* sectionName, const char* key, int newValue)
|
void IniFile::Set(const char* sectionName, const char* key, int newValue)
|
||||||
{
|
{
|
||||||
Set(sectionName, key, StringFromInt(newValue).c_str());
|
Set(sectionName, key, StringFromInt(newValue).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IniFile::Set(const char* sectionName, const char* key, bool newValue)
|
void IniFile::Set(const char* sectionName, const char* key, bool newValue)
|
||||||
{
|
{
|
||||||
Set(sectionName, key, StringFromBool(newValue).c_str());
|
Set(sectionName, key, StringFromBool(newValue).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IniFile::SetLines(const char* sectionName, const std::vector<std::string> &lines)
|
void IniFile::SetLines(const char* sectionName, const std::vector<std::string> &lines)
|
||||||
{
|
{
|
||||||
Section* section = GetOrCreateSection(sectionName);
|
Section* section = GetOrCreateSection(sectionName);
|
||||||
section->lines.clear();
|
section->lines.clear();
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
|
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
|
||||||
{
|
{
|
||||||
section->lines.push_back(*iter);
|
section->lines.push_back(*iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool IniFile::Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue)
|
bool IniFile::Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue)
|
||||||
{
|
{
|
||||||
Section* section = GetSection(sectionName);
|
Section* section = GetSection(sectionName);
|
||||||
|
|
||||||
if (!section)
|
if (!section)
|
||||||
{
|
{
|
||||||
if (defaultValue)
|
if (defaultValue)
|
||||||
{
|
{
|
||||||
*value = defaultValue;
|
*value = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string* line = GetLine(section, key, value, 0);
|
std::string* line = GetLine(section, key, value, 0);
|
||||||
|
|
||||||
if (!line)
|
if (!line)
|
||||||
{
|
{
|
||||||
if (defaultValue)
|
if (defaultValue)
|
||||||
{
|
{
|
||||||
*value = defaultValue;
|
*value = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IniFile::Get(const char* sectionName, const char* key, int* value, int defaultValue)
|
bool IniFile::Get(const char* sectionName, const char* key, int* value, int defaultValue)
|
||||||
{
|
{
|
||||||
std::string temp;
|
std::string temp;
|
||||||
bool retval = Get(sectionName, key, &temp, 0);
|
bool retval = Get(sectionName, key, &temp, 0);
|
||||||
|
|
||||||
if (retval && TryParseInt(temp.c_str(), value))
|
if (retval && TryParseInt(temp.c_str(), value))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
*value = defaultValue;
|
*value = defaultValue;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IniFile::Get(const char* sectionName, const char* key, u32* value, u32 defaultValue)
|
bool IniFile::Get(const char* sectionName, const char* key, u32* value, u32 defaultValue)
|
||||||
{
|
{
|
||||||
std::string temp;
|
std::string temp;
|
||||||
bool retval = Get(sectionName, key, &temp, 0);
|
bool retval = Get(sectionName, key, &temp, 0);
|
||||||
|
|
||||||
if (retval && TryParseUInt(temp.c_str(), value))
|
if (retval && TryParseUInt(temp.c_str(), value))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
*value = defaultValue;
|
*value = defaultValue;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IniFile::Get(const char* sectionName, const char* key, bool* value, bool defaultValue)
|
bool IniFile::Get(const char* sectionName, const char* key, bool* value, bool defaultValue)
|
||||||
{
|
{
|
||||||
std::string temp;
|
std::string temp;
|
||||||
bool retval = Get(sectionName, key, &temp, 0);
|
bool retval = Get(sectionName, key, &temp, 0);
|
||||||
|
|
||||||
if (retval && TryParseBool(temp.c_str(), value))
|
if (retval && TryParseBool(temp.c_str(), value))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
*value = defaultValue;
|
*value = defaultValue;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IniFile::DeleteKey(const char* sectionName, const char* key)
|
bool IniFile::DeleteKey(const char* sectionName, const char* key)
|
||||||
{
|
{
|
||||||
Section* section = GetSection(sectionName);
|
Section* section = GetSection(sectionName);
|
||||||
|
|
||||||
if (!section)
|
if (!section)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string* line = GetLine(section, key, 0, 0);
|
std::string* line = GetLine(section, key, 0, 0);
|
||||||
|
|
||||||
for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
|
for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
|
||||||
{
|
{
|
||||||
if (line == &(*liter))
|
if (line == &(*liter))
|
||||||
{
|
{
|
||||||
section->lines.erase(liter);
|
section->lines.erase(liter);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; //shouldn't happen
|
return false; //shouldn't happen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IniFile::Load(const char* filename)
|
bool IniFile::Load(const char* filename)
|
||||||
{
|
{
|
||||||
sections.clear();
|
sections.clear();
|
||||||
sections.push_back(Section(""));
|
sections.push_back(Section(""));
|
||||||
//first section consists of the comments before the first real section
|
//first section consists of the comments before the first real section
|
||||||
|
|
||||||
std::ifstream in;
|
std::ifstream in;
|
||||||
in.open(filename, std::ios::in);
|
in.open(filename, std::ios::in);
|
||||||
|
|
||||||
if (in.fail())
|
if (in.fail())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!in.eof())
|
while (!in.eof())
|
||||||
{
|
{
|
||||||
char templine[512];
|
char templine[512];
|
||||||
in.getline(templine, 512);
|
in.getline(templine, 512);
|
||||||
std::string line = templine;
|
std::string line = templine;
|
||||||
|
|
||||||
if (in.eof())
|
if (in.eof())
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line.size() > 0)
|
if (line.size() > 0)
|
||||||
{
|
{
|
||||||
if (line[0] == '[')
|
if (line[0] == '[')
|
||||||
{
|
{
|
||||||
size_t endpos = line.find("]");
|
size_t endpos = line.find("]");
|
||||||
|
|
||||||
if (endpos != std::string::npos)
|
if (endpos != std::string::npos)
|
||||||
{
|
{
|
||||||
// New section!
|
// New section!
|
||||||
std::string sub = line.substr(1, endpos - 1);
|
std::string sub = line.substr(1, endpos - 1);
|
||||||
sections.push_back(Section(sub));
|
sections.push_back(Section(sub));
|
||||||
|
|
||||||
if (endpos + 1 < line.size())
|
if (endpos + 1 < line.size())
|
||||||
{
|
{
|
||||||
sections[sections.size() - 1].comment = line.substr(endpos + 1);
|
sections[sections.size() - 1].comment = line.substr(endpos + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sections[sections.size() - 1].lines.push_back(line);
|
sections[sections.size() - 1].lines.push_back(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
in.close();
|
in.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IniFile::Save(const char* filename)
|
bool IniFile::Save(const char* filename)
|
||||||
{
|
{
|
||||||
std::ofstream out;
|
std::ofstream out;
|
||||||
out.open(filename, std::ios::out);
|
out.open(filename, std::ios::out);
|
||||||
|
|
||||||
if (out.fail())
|
if (out.fail())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
||||||
{
|
{
|
||||||
const Section& section = *iter;
|
const Section& section = *iter;
|
||||||
|
|
||||||
if (section.name != "")
|
if (section.name != "")
|
||||||
{
|
{
|
||||||
out << "[" << section.name << "]" << section.comment << std::endl;
|
out << "[" << section.name << "]" << section.comment << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter)
|
for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter)
|
||||||
{
|
{
|
||||||
std::string s = *liter;
|
std::string s = *liter;
|
||||||
out << s << std::endl;
|
out << s << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.close();
|
out.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) const
|
bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) const
|
||||||
{
|
{
|
||||||
const Section* section = GetSection(sectionName);
|
const Section* section = GetSection(sectionName);
|
||||||
|
|
||||||
if (!section)
|
if (!section)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
keys.clear();
|
keys.clear();
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
|
for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
|
||||||
{
|
{
|
||||||
std::string key;
|
std::string key;
|
||||||
ParseLine(*liter, &key, 0, 0);
|
ParseLine(*liter, &key, 0, 0);
|
||||||
keys.push_back(key);
|
keys.push_back(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines) const
|
bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines) const
|
||||||
{
|
{
|
||||||
const Section* section = GetSection(sectionName);
|
const Section* section = GetSection(sectionName);
|
||||||
if (!section)
|
if (!section)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
lines.clear();
|
lines.clear();
|
||||||
for (std::vector<std::string>::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
|
for (std::vector<std::string>::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
|
||||||
{
|
{
|
||||||
std::string line = StripSpaces(*iter);
|
std::string line = StripSpaces(*iter);
|
||||||
int commentPos = (int)line.find('#');
|
int commentPos = (int)line.find('#');
|
||||||
if (commentPos == 0)
|
if (commentPos == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commentPos != (int)std::string::npos)
|
if (commentPos != (int)std::string::npos)
|
||||||
{
|
{
|
||||||
line = StripSpaces(line.substr(0, commentPos));
|
line = StripSpaces(line.substr(0, commentPos));
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.push_back(line);
|
lines.push_back(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IniFile::SortSections()
|
void IniFile::SortSections()
|
||||||
{
|
{
|
||||||
std::sort(sections.begin(), sections.end());
|
std::sort(sections.begin(), sections.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
IniFile ini;
|
IniFile ini;
|
||||||
ini.Load("my.ini");
|
ini.Load("my.ini");
|
||||||
ini.Set("Hej", "A", "amaskdfl");
|
ini.Set("Hej", "A", "amaskdfl");
|
||||||
ini.Set("Mossa", "A", "amaskdfl");
|
ini.Set("Mossa", "A", "amaskdfl");
|
||||||
ini.Set("Aissa", "A", "amaskdfl");
|
ini.Set("Aissa", "A", "amaskdfl");
|
||||||
//ini.Read("my.ini");
|
//ini.Read("my.ini");
|
||||||
std::string x;
|
std::string x;
|
||||||
ini.Get("Hej", "B", &x, "boo");
|
ini.Get("Hej", "B", &x, "boo");
|
||||||
ini.DeleteKey("Mossa", "A");
|
ini.DeleteKey("Mossa", "A");
|
||||||
ini.DeleteSection("Mossa");
|
ini.DeleteSection("Mossa");
|
||||||
ini.SortSections();
|
ini.SortSections();
|
||||||
ini.Save("my.ini");
|
ini.Save("my.ini");
|
||||||
//UpdateVars(ini);
|
//UpdateVars(ini);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -1,233 +1,233 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "MappedFile.h"
|
#include "MappedFile.h"
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
class CMappedFile
|
class CMappedFile
|
||||||
: public IMappedFile
|
: public IMappedFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CMappedFile(void);
|
CMappedFile(void);
|
||||||
~CMappedFile(void);
|
~CMappedFile(void);
|
||||||
bool Open(const char* _szFilename);
|
bool Open(const char* _szFilename);
|
||||||
bool IsOpen(void);
|
bool IsOpen(void);
|
||||||
void Close(void);
|
void Close(void);
|
||||||
u64 GetSize(void);
|
u64 GetSize(void);
|
||||||
u8* Lock(u64 _offset, u64 _size);
|
u8* Lock(u64 _offset, u64 _size);
|
||||||
void Unlock(u8* ptr);
|
void Unlock(u8* ptr);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
u64 size;
|
u64 size;
|
||||||
|
|
||||||
typedef std::map<u8*, u8*>Lockmap;
|
typedef std::map<u8*, u8*>Lockmap;
|
||||||
Lockmap lockMap;
|
Lockmap lockMap;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE hFile;
|
HANDLE hFile;
|
||||||
HANDLE hFileMapping;
|
HANDLE hFileMapping;
|
||||||
#elif POSIX
|
#elif POSIX
|
||||||
int fd;
|
int fd;
|
||||||
typedef std::map<u8*, size_t>Sizemap;
|
typedef std::map<u8*, size_t>Sizemap;
|
||||||
Sizemap sizeMap;
|
Sizemap sizeMap;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int granularity;
|
int granularity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
CMappedFile::CMappedFile()
|
CMappedFile::CMappedFile()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
hFile = INVALID_HANDLE_VALUE;
|
hFile = INVALID_HANDLE_VALUE;
|
||||||
SYSTEM_INFO info;
|
SYSTEM_INFO info;
|
||||||
GetSystemInfo(&info);
|
GetSystemInfo(&info);
|
||||||
granularity = (int)info.dwAllocationGranularity;
|
granularity = (int)info.dwAllocationGranularity;
|
||||||
#elif POSIX
|
#elif POSIX
|
||||||
fd = -1;
|
fd = -1;
|
||||||
granularity = getpagesize(); //sysconf(_SC_PAGE_SIZE);
|
granularity = getpagesize(); //sysconf(_SC_PAGE_SIZE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CMappedFile::~CMappedFile()
|
CMappedFile::~CMappedFile()
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CMappedFile::Open(const char* filename)
|
bool CMappedFile::Open(const char* filename)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
|
||||||
if (hFile == INVALID_HANDLE_VALUE)
|
if (hFile == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
hFileMapping = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, NULL);
|
hFileMapping = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, NULL);
|
||||||
|
|
||||||
if (hFileMapping == NULL)
|
if (hFileMapping == NULL)
|
||||||
{
|
{
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
hFile = 0;
|
hFile = 0;
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 high = 0;
|
u32 high = 0;
|
||||||
u32 low = GetFileSize(hFile, (LPDWORD)&high);
|
u32 low = GetFileSize(hFile, (LPDWORD)&high);
|
||||||
size = (u64)low | ((u64)high << 32);
|
size = (u64)low | ((u64)high << 32);
|
||||||
#elif POSIX
|
#elif POSIX
|
||||||
fd = open(filename, O_RDONLY);
|
fd = open(filename, O_RDONLY);
|
||||||
size = lseek(fd, 0, SEEK_END);
|
size = lseek(fd, 0, SEEK_END);
|
||||||
lseek(fd, 0, SEEK_SET);
|
lseek(fd, 0, SEEK_SET);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CMappedFile::IsOpen()
|
bool CMappedFile::IsOpen()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return(hFile != INVALID_HANDLE_VALUE);
|
return(hFile != INVALID_HANDLE_VALUE);
|
||||||
|
|
||||||
#elif POSIX
|
#elif POSIX
|
||||||
return(fd != -1);
|
return(fd != -1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
u64 CMappedFile::GetSize()
|
u64 CMappedFile::GetSize()
|
||||||
{
|
{
|
||||||
return(size);
|
return(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CMappedFile::Close()
|
void CMappedFile::Close()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (hFile != INVALID_HANDLE_VALUE)
|
if (hFile != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
CloseHandle(hFileMapping);
|
CloseHandle(hFileMapping);
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
lockMap.clear();
|
lockMap.clear();
|
||||||
hFile = INVALID_HANDLE_VALUE;
|
hFile = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif POSIX
|
#elif POSIX
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
{
|
{
|
||||||
lockMap.clear();
|
lockMap.clear();
|
||||||
sizeMap.clear();
|
sizeMap.clear();
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = -1;
|
fd = -1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
u8* CMappedFile::Lock(u64 offset, u64 _size)
|
u8* CMappedFile::Lock(u64 offset, u64 _size)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (hFile != INVALID_HANDLE_VALUE)
|
if (hFile != INVALID_HANDLE_VALUE)
|
||||||
#elif POSIX
|
#elif POSIX
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
u64 realOffset = offset & ~(granularity - 1);
|
u64 realOffset = offset & ~(granularity - 1);
|
||||||
s64 difference = offset - realOffset;
|
s64 difference = offset - realOffset;
|
||||||
u64 fake_size = (difference + _size + granularity - 1) & ~(granularity - 1);
|
u64 fake_size = (difference + _size + granularity - 1) & ~(granularity - 1);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
u8* realPtr = (u8*)MapViewOfFile(hFileMapping, FILE_MAP_READ, (DWORD)(realOffset >> 32), (DWORD)realOffset, (SIZE_T)(_size));
|
u8* realPtr = (u8*)MapViewOfFile(hFileMapping, FILE_MAP_READ, (DWORD)(realOffset >> 32), (DWORD)realOffset, (SIZE_T)(_size));
|
||||||
|
|
||||||
if (realPtr == NULL)
|
if (realPtr == NULL)
|
||||||
{
|
{
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif POSIX
|
#elif POSIX
|
||||||
// TODO
|
// TODO
|
||||||
u8* realPtr = (u8*)mmap(0, fake_size, PROT_READ, MAP_PRIVATE, fd, (off_t)realOffset);
|
u8* realPtr = (u8*)mmap(0, fake_size, PROT_READ, MAP_PRIVATE, fd, (off_t)realOffset);
|
||||||
|
|
||||||
if (!realPtr)
|
if (!realPtr)
|
||||||
{
|
{
|
||||||
PanicAlert("Map Failed");
|
PanicAlert("Map Failed");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
u8* fakePtr = realPtr + difference;
|
u8* fakePtr = realPtr + difference;
|
||||||
//add to map
|
//add to map
|
||||||
lockMap[fakePtr] = realPtr;
|
lockMap[fakePtr] = realPtr;
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
sizeMap[fakePtr] = _size + difference;
|
sizeMap[fakePtr] = _size + difference;
|
||||||
#endif
|
#endif
|
||||||
return(fakePtr);
|
return(fakePtr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CMappedFile::Unlock(u8* ptr)
|
void CMappedFile::Unlock(u8* ptr)
|
||||||
{
|
{
|
||||||
if (ptr != 0)
|
if (ptr != 0)
|
||||||
{
|
{
|
||||||
Lockmap::iterator iter = lockMap.find(ptr);
|
Lockmap::iterator iter = lockMap.find(ptr);
|
||||||
|
|
||||||
if (iter != lockMap.end())
|
if (iter != lockMap.end())
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
UnmapViewOfFile((*iter).second);
|
UnmapViewOfFile((*iter).second);
|
||||||
#else
|
#else
|
||||||
munmap((*iter).second, sizeMap[ptr]);
|
munmap((*iter).second, sizeMap[ptr]);
|
||||||
#endif
|
#endif
|
||||||
lockMap.erase(iter);
|
lockMap.erase(iter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PanicAlert("CMappedFile : Unlock failed");
|
PanicAlert("CMappedFile : Unlock failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
IMappedFile* IMappedFile::CreateMappedFileDEPRECATED(void)
|
IMappedFile* IMappedFile::CreateMappedFileDEPRECATED(void)
|
||||||
{
|
{
|
||||||
return(new CMappedFile);
|
return(new CMappedFile);
|
||||||
}
|
}
|
||||||
} // end of namespace Common
|
} // end of namespace Common
|
||||||
|
|
|
@ -1,44 +1,44 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "MathUtil.h"
|
#include "MathUtil.h"
|
||||||
|
|
||||||
static u32 saved_sse_state = _mm_getcsr();
|
static u32 saved_sse_state = _mm_getcsr();
|
||||||
static const u32 default_sse_state = _mm_getcsr();
|
static const u32 default_sse_state = _mm_getcsr();
|
||||||
|
|
||||||
|
|
||||||
void LoadDefaultSSEState()
|
void LoadDefaultSSEState()
|
||||||
{
|
{
|
||||||
_mm_setcsr(default_sse_state);
|
_mm_setcsr(default_sse_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LoadSSEState()
|
void LoadSSEState()
|
||||||
{
|
{
|
||||||
_mm_setcsr(saved_sse_state);
|
_mm_setcsr(saved_sse_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SaveSSEState()
|
void SaveSSEState()
|
||||||
{
|
{
|
||||||
saved_sse_state = _mm_getcsr();
|
saved_sse_state = _mm_getcsr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,144 +1,144 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "MemArena.h"
|
#include "MemArena.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
|
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
|
||||||
#define MAP_ANONYMOUS MAP_ANON
|
#define MAP_ANONYMOUS MAP_ANON
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
const char* ram_temp_file = "/tmp/gc_mem.tmp";
|
const char* ram_temp_file = "/tmp/gc_mem.tmp";
|
||||||
|
|
||||||
void MemArena::GrabLowMemSpace(size_t size)
|
void MemArena::GrabLowMemSpace(size_t size)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
hMemoryMapping = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0, (DWORD)(size), _T("All GC Memory"));
|
hMemoryMapping = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0, (DWORD)(size), _T("All GC Memory"));
|
||||||
#else
|
#else
|
||||||
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||||
fd = open(ram_temp_file, O_RDWR | O_CREAT, mode);
|
fd = open(ram_temp_file, O_RDWR | O_CREAT, mode);
|
||||||
ftruncate(fd, size);
|
ftruncate(fd, size);
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MemArena::ReleaseSpace()
|
void MemArena::ReleaseSpace()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
CloseHandle(hMemoryMapping);
|
CloseHandle(hMemoryMapping);
|
||||||
hMemoryMapping = 0;
|
hMemoryMapping = 0;
|
||||||
#else
|
#else
|
||||||
close(fd);
|
close(fd);
|
||||||
unlink(ram_temp_file);
|
unlink(ram_temp_file);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void* MemArena::CreateView(s64 offset, size_t size, bool ensure_low_mem)
|
void* MemArena::CreateView(s64 offset, size_t size, bool ensure_low_mem)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return(MapViewOfFile(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size));
|
return(MapViewOfFile(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
void* ptr = mmap(0, size,
|
void* ptr = mmap(0, size,
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED
|
MAP_SHARED
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
| (ensure_low_mem ? MAP_32BIT : 0)
|
| (ensure_low_mem ? MAP_32BIT : 0)
|
||||||
#endif
|
#endif
|
||||||
, fd, offset);
|
, fd, offset);
|
||||||
|
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
{
|
{
|
||||||
PanicAlert("Failed to create view");
|
PanicAlert("Failed to create view");
|
||||||
}
|
}
|
||||||
|
|
||||||
return(ptr);
|
return(ptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void* MemArena::CreateViewAt(s64 offset, size_t size, void* base)
|
void* MemArena::CreateViewAt(s64 offset, size_t size, void* base)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return(MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base));
|
return(MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
return(mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, offset));
|
return(mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, offset));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MemArena::ReleaseView(void* view, size_t size)
|
void MemArena::ReleaseView(void* view, size_t size)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
UnmapViewOfFile(view);
|
UnmapViewOfFile(view);
|
||||||
#else
|
#else
|
||||||
munmap(view, size);
|
munmap(view, size);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
u8* MemArena::Find4GBBase()
|
u8* MemArena::Find4GBBase()
|
||||||
{
|
{
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// 64 bit
|
// 64 bit
|
||||||
u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE);
|
u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE);
|
||||||
VirtualFree(base, 0, MEM_RELEASE);
|
VirtualFree(base, 0, MEM_RELEASE);
|
||||||
return base;
|
return base;
|
||||||
#else
|
#else
|
||||||
// Very precarious - mmap cannot return an error when trying to map already used pages.
|
// Very precarious - mmap cannot return an error when trying to map already used pages.
|
||||||
// This makes the Windows approach above unusable on Linux, so we will simply pray...
|
// This makes the Windows approach above unusable on Linux, so we will simply pray...
|
||||||
return reinterpret_cast<u8*>(0x2300000000ULL);
|
return reinterpret_cast<u8*>(0x2300000000ULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// 32 bit
|
// 32 bit
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it.
|
// The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it.
|
||||||
u8* base = (u8*)VirtualAlloc(0, 0x31000000, MEM_RESERVE, PAGE_READWRITE);
|
u8* base = (u8*)VirtualAlloc(0, 0x31000000, MEM_RESERVE, PAGE_READWRITE);
|
||||||
if (base) {
|
if (base) {
|
||||||
VirtualFree(base, 0, MEM_RELEASE);
|
VirtualFree(base, 0, MEM_RELEASE);
|
||||||
}
|
}
|
||||||
return base;
|
return base;
|
||||||
#else
|
#else
|
||||||
void* base = mmap(0, 0x31000000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0);
|
void* base = mmap(0, 0x31000000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0);
|
||||||
if (base == MAP_FAILED) {
|
if (base == MAP_FAILED) {
|
||||||
PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno));
|
PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
munmap(base, 0x31000000);
|
munmap(base, 0x31000000);
|
||||||
return static_cast<u8*>(base);
|
return static_cast<u8*>(base);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,135 +1,135 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "MemoryUtil.h"
|
#include "MemoryUtil.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#elif __GNUC__
|
#elif __GNUC__
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
|
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
|
||||||
#define MAP_ANONYMOUS MAP_ANON
|
#define MAP_ANONYMOUS MAP_ANON
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// MacOSX does not support MAP_VARIABLE
|
// MacOSX does not support MAP_VARIABLE
|
||||||
#ifndef MAP_VARIABLE
|
#ifndef MAP_VARIABLE
|
||||||
#define MAP_VARIABLE 0
|
#define MAP_VARIABLE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This is purposedely not a full wrapper for virtualalloc/mmap, but it
|
// This is purposedely not a full wrapper for virtualalloc/mmap, but it
|
||||||
// provides exactly the primitive operations that Dolphin needs.
|
// provides exactly the primitive operations that Dolphin needs.
|
||||||
|
|
||||||
void* AllocateExecutableMemory(int size, bool low)
|
void* AllocateExecutableMemory(int size, bool low)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||||
|
|
||||||
if ((u64)ptr >= 0x80000000)
|
if ((u64)ptr >= 0x80000000)
|
||||||
{
|
{
|
||||||
PanicAlert("Executable memory ended up above 2GB!");
|
PanicAlert("Executable memory ended up above 2GB!");
|
||||||
// If this happens, we have to implement a free ram search scheme. ector knows how.
|
// If this happens, we have to implement a free ram search scheme. ector knows how.
|
||||||
}
|
}
|
||||||
|
|
||||||
return(ptr);
|
return(ptr);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
void* retval = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC,
|
void* retval = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||||
MAP_ANONYMOUS | MAP_PRIVATE
|
MAP_ANONYMOUS | MAP_PRIVATE
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
| (low ? MAP_32BIT : 0)
|
| (low ? MAP_32BIT : 0)
|
||||||
#endif
|
#endif
|
||||||
, -1, 0); // | MAP_FIXED
|
, -1, 0); // | MAP_FIXED
|
||||||
// printf("Mapped executable memory at %p (size %i)\n", retval, size);
|
// printf("Mapped executable memory at %p (size %i)\n", retval, size);
|
||||||
|
|
||||||
if (!retval)
|
if (!retval)
|
||||||
{
|
{
|
||||||
PanicAlert("Failed to allocate executable memory, errno=%i", errno);
|
PanicAlert("Failed to allocate executable memory, errno=%i", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(retval);
|
return(retval);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void* AllocateMemoryPages(int size)
|
void* AllocateMemoryPages(int size)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
|
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
{
|
{
|
||||||
PanicAlert("Failed to allocate raw memory");
|
PanicAlert("Failed to allocate raw memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
return(ptr);
|
return(ptr);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
void* retval = mmap(0, size, PROT_READ | PROT_WRITE,
|
void* retval = mmap(0, size, PROT_READ | PROT_WRITE,
|
||||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // | MAP_FIXED
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // | MAP_FIXED
|
||||||
// printf("Mapped memory at %p (size %i)\n", retval, size);
|
// printf("Mapped memory at %p (size %i)\n", retval, size);
|
||||||
|
|
||||||
if (!retval)
|
if (!retval)
|
||||||
{
|
{
|
||||||
PanicAlert("Failed to allocate raw memory, errno=%i", errno);
|
PanicAlert("Failed to allocate raw memory, errno=%i", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(retval);
|
return(retval);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FreeMemoryPages(void* ptr, int size)
|
void FreeMemoryPages(void* ptr, int size)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (ptr)
|
if (ptr)
|
||||||
{
|
{
|
||||||
VirtualFree(ptr, 0, MEM_RELEASE);
|
VirtualFree(ptr, 0, MEM_RELEASE);
|
||||||
ptr = NULL;
|
ptr = NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
munmap(ptr, size);
|
munmap(ptr, size);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WriteProtectMemory(void* ptr, int size, bool allowExecute)
|
void WriteProtectMemory(void* ptr, int size, bool allowExecute)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, 0);
|
VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, 0);
|
||||||
#else
|
#else
|
||||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
|
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UnWriteProtectMemory(void* ptr, int size, bool allowExecute)
|
void UnWriteProtectMemory(void* ptr, int size, bool allowExecute)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READONLY, 0);
|
VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READONLY, 0);
|
||||||
#else
|
#else
|
||||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
|
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,100 +1,100 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// File description
|
// File description
|
||||||
// -------------
|
// -------------
|
||||||
/* This file is a simpler version of Plugin_...cpp found in Core. This file only loads
|
/* This file is a simpler version of Plugin_...cpp found in Core. This file only loads
|
||||||
the config and debugging windowses and works with all plugins. */
|
the config and debugging windowses and works with all plugins. */
|
||||||
// =============
|
// =============
|
||||||
|
|
||||||
|
|
||||||
#include "Plugin.h"
|
#include "Plugin.h"
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
DynamicLibrary CPlugin::m_hInstLib;
|
DynamicLibrary CPlugin::m_hInstLib;
|
||||||
|
|
||||||
void(__cdecl * CPlugin::m_GetDllInfo) (PLUGIN_INFO * _PluginInfo) = 0;
|
void(__cdecl * CPlugin::m_GetDllInfo) (PLUGIN_INFO * _PluginInfo) = 0;
|
||||||
//void(__cdecl * CPlugin::m_DllAbout) (HWND _hParent) = 0;
|
//void(__cdecl * CPlugin::m_DllAbout) (HWND _hParent) = 0;
|
||||||
void(__cdecl * CPlugin::m_DllConfig) (HWND _hParent) = 0;
|
void(__cdecl * CPlugin::m_DllConfig) (HWND _hParent) = 0;
|
||||||
void(__cdecl * CPlugin::m_DllDebugger) (HWND _hParent, bool Show) = 0;
|
void(__cdecl * CPlugin::m_DllDebugger) (HWND _hParent, bool Show) = 0;
|
||||||
|
|
||||||
void
|
void
|
||||||
CPlugin::Release(void)
|
CPlugin::Release(void)
|
||||||
{
|
{
|
||||||
m_GetDllInfo = 0;
|
m_GetDllInfo = 0;
|
||||||
//m_DllAbout = 0;
|
//m_DllAbout = 0;
|
||||||
m_DllConfig = 0;
|
m_DllConfig = 0;
|
||||||
m_DllDebugger = 0;
|
m_DllDebugger = 0;
|
||||||
|
|
||||||
m_hInstLib.Unload();
|
m_hInstLib.Unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CPlugin::Load(const char* _szName)
|
CPlugin::Load(const char* _szName)
|
||||||
{
|
{
|
||||||
if (m_hInstLib.Load(_szName))
|
if (m_hInstLib.Load(_szName))
|
||||||
{
|
{
|
||||||
m_GetDllInfo = (void (__cdecl*)(PLUGIN_INFO*)) m_hInstLib.Get("GetDllInfo");
|
m_GetDllInfo = (void (__cdecl*)(PLUGIN_INFO*)) m_hInstLib.Get("GetDllInfo");
|
||||||
m_DllConfig = (void (__cdecl*)(HWND)) m_hInstLib.Get("DllConfig");
|
m_DllConfig = (void (__cdecl*)(HWND)) m_hInstLib.Get("DllConfig");
|
||||||
m_DllDebugger = (void (__cdecl*)(HWND, bool)) m_hInstLib.Get("DllDebugger");
|
m_DllDebugger = (void (__cdecl*)(HWND, bool)) m_hInstLib.Get("DllDebugger");
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CPlugin::GetInfo(PLUGIN_INFO& _pluginInfo)
|
bool CPlugin::GetInfo(PLUGIN_INFO& _pluginInfo)
|
||||||
{
|
{
|
||||||
if (m_GetDllInfo != 0)
|
if (m_GetDllInfo != 0)
|
||||||
{
|
{
|
||||||
m_GetDllInfo(&_pluginInfo);
|
m_GetDllInfo(&_pluginInfo);
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CPlugin::Config(HWND _hwnd)
|
void CPlugin::Config(HWND _hwnd)
|
||||||
{
|
{
|
||||||
if (m_DllConfig != 0)
|
if (m_DllConfig != 0)
|
||||||
{
|
{
|
||||||
m_DllConfig(_hwnd);
|
m_DllConfig(_hwnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//void CPlugin::About(HWND _hwnd)
|
//void CPlugin::About(HWND _hwnd)
|
||||||
//{
|
//{
|
||||||
// if (m_DllAbout != 0)
|
// if (m_DllAbout != 0)
|
||||||
// {
|
// {
|
||||||
// m_DllAbout(_hwnd);
|
// m_DllAbout(_hwnd);
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
void CPlugin::Debug(HWND _hwnd, bool Show)
|
void CPlugin::Debug(HWND _hwnd, bool Show)
|
||||||
{
|
{
|
||||||
if (m_DllDebugger != 0)
|
if (m_DllDebugger != 0)
|
||||||
{
|
{
|
||||||
m_DllDebugger(_hwnd, Show);
|
m_DllDebugger(_hwnd, Show);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end of namespace Common
|
} // end of namespace Common
|
||||||
|
|
|
@ -1,396 +1,396 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "TestFramework.h"
|
#include "TestFramework.h"
|
||||||
|
|
||||||
// faster than sscanf
|
// faster than sscanf
|
||||||
bool AsciiToHex(const char* _szValue, u32& result)
|
bool AsciiToHex(const char* _szValue, u32& result)
|
||||||
{
|
{
|
||||||
u32 value = 0;
|
u32 value = 0;
|
||||||
size_t finish = strlen(_szValue);
|
size_t finish = strlen(_szValue);
|
||||||
|
|
||||||
if (finish > 8)
|
if (finish > 8)
|
||||||
finish = 8; // Max 32-bit values are supported.
|
finish = 8; // Max 32-bit values are supported.
|
||||||
|
|
||||||
for (size_t count = 0; count < finish; count++)
|
for (size_t count = 0; count < finish; count++)
|
||||||
{
|
{
|
||||||
value <<= 4;
|
value <<= 4;
|
||||||
switch (_szValue[count])
|
switch (_szValue[count])
|
||||||
{
|
{
|
||||||
case '0': break;
|
case '0': break;
|
||||||
case '1': value += 1; break;
|
case '1': value += 1; break;
|
||||||
case '2': value += 2; break;
|
case '2': value += 2; break;
|
||||||
case '3': value += 3; break;
|
case '3': value += 3; break;
|
||||||
case '4': value += 4; break;
|
case '4': value += 4; break;
|
||||||
case '5': value += 5; break;
|
case '5': value += 5; break;
|
||||||
case '6': value += 6; break;
|
case '6': value += 6; break;
|
||||||
case '7': value += 7; break;
|
case '7': value += 7; break;
|
||||||
case '8': value += 8; break;
|
case '8': value += 8; break;
|
||||||
case '9': value += 9; break;
|
case '9': value += 9; break;
|
||||||
case 'A':
|
case 'A':
|
||||||
case 'a': value += 10; break;
|
case 'a': value += 10; break;
|
||||||
case 'B':
|
case 'B':
|
||||||
case 'b': value += 11; break;
|
case 'b': value += 11; break;
|
||||||
case 'C':
|
case 'C':
|
||||||
case 'c': value += 12; break;
|
case 'c': value += 12; break;
|
||||||
case 'D':
|
case 'D':
|
||||||
case 'd': value += 13; break;
|
case 'd': value += 13; break;
|
||||||
case 'E':
|
case 'E':
|
||||||
case 'e': value += 14; break;
|
case 'e': value += 14; break;
|
||||||
case 'F':
|
case 'F':
|
||||||
case 'f': value += 15; break;
|
case 'f': value += 15; break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = value;
|
result = value;
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args)
|
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args)
|
||||||
{
|
{
|
||||||
int writtenCount = vsnprintf(out, outsize, format, args);
|
int writtenCount = vsnprintf(out, outsize, format, args);
|
||||||
|
|
||||||
if (writtenCount > 0 && writtenCount < outsize)
|
if (writtenCount > 0 && writtenCount < outsize)
|
||||||
{
|
{
|
||||||
out[writtenCount] = '\0';
|
out[writtenCount] = '\0';
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out[outsize - 1] = '\0';
|
out[outsize - 1] = '\0';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Expensive!
|
// Expensive!
|
||||||
void StringFromFormatV(std::string* out, const char* format, va_list args)
|
void StringFromFormatV(std::string* out, const char* format, va_list args)
|
||||||
{
|
{
|
||||||
int writtenCount = -1;
|
int writtenCount = -1;
|
||||||
size_t newSize = strlen(format) + 16;
|
size_t newSize = strlen(format) + 16;
|
||||||
char* buf = 0;
|
char* buf = 0;
|
||||||
|
|
||||||
while (writtenCount < 0)
|
while (writtenCount < 0)
|
||||||
{
|
{
|
||||||
delete [] buf;
|
delete [] buf;
|
||||||
buf = new char[newSize + 1];
|
buf = new char[newSize + 1];
|
||||||
writtenCount = vsnprintf(buf, newSize, format, args);
|
writtenCount = vsnprintf(buf, newSize, format, args);
|
||||||
if (writtenCount > (int)newSize)
|
if (writtenCount > (int)newSize)
|
||||||
writtenCount = -1;
|
writtenCount = -1;
|
||||||
// ARGH! vsnprintf does no longer return -1 on truncation in newer libc!
|
// ARGH! vsnprintf does no longer return -1 on truncation in newer libc!
|
||||||
// WORKAROUND! let's fake the old behaviour (even though it's less efficient).
|
// WORKAROUND! let's fake the old behaviour (even though it's less efficient).
|
||||||
// TODO: figure out why the fix causes an invalid read in strlen called from vsnprintf :(
|
// TODO: figure out why the fix causes an invalid read in strlen called from vsnprintf :(
|
||||||
// if (writtenCount >= (int)newSize)
|
// if (writtenCount >= (int)newSize)
|
||||||
// writtenCount = -1;
|
// writtenCount = -1;
|
||||||
newSize *= 2;
|
newSize *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[writtenCount] = '\0';
|
buf[writtenCount] = '\0';
|
||||||
*out = buf;
|
*out = buf;
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string StringFromFormat(const char* format, ...)
|
std::string StringFromFormat(const char* format, ...)
|
||||||
{
|
{
|
||||||
std::string temp;
|
std::string temp;
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
StringFromFormatV(&temp, format, args);
|
StringFromFormatV(&temp, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return(temp);
|
return(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ToStringFromFormat(std::string* out, const char* format, ...)
|
void ToStringFromFormat(std::string* out, const char* format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
StringFromFormatV(out, format, args);
|
StringFromFormatV(out, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Turns " hej " into "hej". Also handles tabs.
|
// Turns " hej " into "hej". Also handles tabs.
|
||||||
std::string StripSpaces(const std::string &str)
|
std::string StripSpaces(const std::string &str)
|
||||||
{
|
{
|
||||||
std::string s = str;
|
std::string s = str;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < (int)s.size(); i++)
|
for (i = 0; i < (int)s.size(); i++)
|
||||||
{
|
{
|
||||||
if ((s[i] != ' ') && (s[i] != 9))
|
if ((s[i] != ' ') && (s[i] != 9))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s = s.substr(i);
|
s = s.substr(i);
|
||||||
|
|
||||||
for (i = (int)s.size() - 1; i > 0; i--)
|
for (i = (int)s.size() - 1; i > 0; i--)
|
||||||
{
|
{
|
||||||
if ((s[i] != ' ') && (s[i] != 9))
|
if ((s[i] != ' ') && (s[i] != 9))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.substr(0, i + 1);
|
return s.substr(0, i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// "\"hello\"" is turned to "hello"
|
// "\"hello\"" is turned to "hello"
|
||||||
// This one assumes that the string has already been space stripped in both
|
// This one assumes that the string has already been space stripped in both
|
||||||
// ends, as done by StripSpaces above, for example.
|
// ends, as done by StripSpaces above, for example.
|
||||||
std::string StripQuotes(const std::string& s)
|
std::string StripQuotes(const std::string& s)
|
||||||
{
|
{
|
||||||
if ((s[0] == '\"') && (s[s.size() - 1] == '\"'))
|
if ((s[0] == '\"') && (s[s.size() - 1] == '\"'))
|
||||||
return s.substr(1, s.size() - 2);
|
return s.substr(1, s.size() - 2);
|
||||||
else
|
else
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "\"hello\"" is turned to "hello"
|
// "\"hello\"" is turned to "hello"
|
||||||
// This one assumes that the string has already been space stripped in both
|
// This one assumes that the string has already been space stripped in both
|
||||||
// ends, as done by StripSpaces above, for example.
|
// ends, as done by StripSpaces above, for example.
|
||||||
std::string StripNewline(const std::string& s)
|
std::string StripNewline(const std::string& s)
|
||||||
{
|
{
|
||||||
if (!s.size())
|
if (!s.size())
|
||||||
return s;
|
return s;
|
||||||
else if (s[s.size() - 1] == '\n')
|
else if (s[s.size() - 1] == '\n')
|
||||||
return s.substr(0, s.size() - 1);
|
return s.substr(0, s.size() - 1);
|
||||||
else
|
else
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryParseInt(const char* str, int* outVal)
|
bool TryParseInt(const char* str, int* outVal)
|
||||||
{
|
{
|
||||||
const char* s = str;
|
const char* s = str;
|
||||||
int value = 0;
|
int value = 0;
|
||||||
bool negativ = false;
|
bool negativ = false;
|
||||||
|
|
||||||
if (*s == '-')
|
if (*s == '-')
|
||||||
{
|
{
|
||||||
negativ = true;
|
negativ = true;
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (*s)
|
while (*s)
|
||||||
{
|
{
|
||||||
char c = *s++;
|
char c = *s++;
|
||||||
|
|
||||||
if ((c < '0') || (c > '9'))
|
if ((c < '0') || (c > '9'))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = value * 10 + (c - '0');
|
value = value * 10 + (c - '0');
|
||||||
}
|
}
|
||||||
if (negativ)
|
if (negativ)
|
||||||
value = -value;
|
value = -value;
|
||||||
|
|
||||||
*outVal = value;
|
*outVal = value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TryParseBool(const char* str, bool* output)
|
bool TryParseBool(const char* str, bool* output)
|
||||||
{
|
{
|
||||||
if ((str[0] == '1') || !strcmp(str, "true") || !strcmp(str, "True") || !strcmp(str, "TRUE"))
|
if ((str[0] == '1') || !strcmp(str, "true") || !strcmp(str, "True") || !strcmp(str, "TRUE"))
|
||||||
{
|
{
|
||||||
*output = true;
|
*output = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (str[0] == '0' || !strcmp(str, "false") || !strcmp(str, "False") || !strcmp(str, "FALSE"))
|
else if (str[0] == '0' || !strcmp(str, "false") || !strcmp(str, "False") || !strcmp(str, "FALSE"))
|
||||||
{
|
{
|
||||||
*output = false;
|
*output = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string StringFromInt(int value)
|
std::string StringFromInt(int value)
|
||||||
{
|
{
|
||||||
char temp[16];
|
char temp[16];
|
||||||
sprintf(temp, "%i", value);
|
sprintf(temp, "%i", value);
|
||||||
return std::string(temp);
|
return std::string(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string StringFromBool(bool value)
|
std::string StringFromBool(bool value)
|
||||||
{
|
{
|
||||||
return value ? "True" : "False";
|
return value ? "True" : "False";
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
|
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
|
||||||
{
|
{
|
||||||
char drive[_MAX_DRIVE];
|
char drive[_MAX_DRIVE];
|
||||||
char dir[_MAX_DIR];
|
char dir[_MAX_DIR];
|
||||||
char fname[_MAX_FNAME];
|
char fname[_MAX_FNAME];
|
||||||
char ext[_MAX_EXT];
|
char ext[_MAX_EXT];
|
||||||
|
|
||||||
if (_splitpath_s(full_path.c_str(), drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT) == 0)
|
if (_splitpath_s(full_path.c_str(), drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT) == 0)
|
||||||
{
|
{
|
||||||
if (_pPath)
|
if (_pPath)
|
||||||
{
|
{
|
||||||
*_pPath = std::string(drive) + std::string(dir);
|
*_pPath = std::string(drive) + std::string(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pFilename != 0)
|
if (_pFilename != 0)
|
||||||
{
|
{
|
||||||
*_pFilename = fname;
|
*_pFilename = fname;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pExtension != 0)
|
if (_pExtension != 0)
|
||||||
{
|
{
|
||||||
*_pExtension = ext;
|
*_pExtension = ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
|
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
|
||||||
{
|
{
|
||||||
size_t last_slash = full_path.rfind('/');
|
size_t last_slash = full_path.rfind('/');
|
||||||
|
|
||||||
if (last_slash == std::string::npos)
|
if (last_slash == std::string::npos)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t last_dot = full_path.rfind('.');
|
size_t last_dot = full_path.rfind('.');
|
||||||
|
|
||||||
if ((last_dot == std::string::npos) || (last_dot < last_slash))
|
if ((last_dot == std::string::npos) || (last_dot < last_slash))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pPath)
|
if (_pPath)
|
||||||
{
|
{
|
||||||
*_pPath = full_path.substr(0, last_slash + 1);
|
*_pPath = full_path.substr(0, last_slash + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pFilename)
|
if (_pFilename)
|
||||||
{
|
{
|
||||||
*_pFilename = full_path.substr(last_slash + 1, last_dot - (last_slash + 1));
|
*_pFilename = full_path.substr(last_slash + 1, last_dot - (last_slash + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pExtension)
|
if (_pExtension)
|
||||||
{
|
{
|
||||||
*_pExtension = full_path.substr(last_dot + 1);
|
*_pExtension = full_path.substr(last_dot + 1);
|
||||||
_pExtension->insert(0, ".");
|
_pExtension->insert(0, ".");
|
||||||
}
|
}
|
||||||
else if (_pFilename)
|
else if (_pFilename)
|
||||||
{
|
{
|
||||||
*_pFilename += full_path.substr(last_dot);
|
*_pFilename += full_path.substr(last_dot);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename)
|
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename)
|
||||||
{
|
{
|
||||||
_CompleteFilename = _Path;
|
_CompleteFilename = _Path;
|
||||||
|
|
||||||
// check for seperator
|
// check for seperator
|
||||||
if (_CompleteFilename[_CompleteFilename.size() - 1] != '\\')
|
if (_CompleteFilename[_CompleteFilename.size() - 1] != '\\')
|
||||||
{
|
{
|
||||||
_CompleteFilename += "\\";
|
_CompleteFilename += "\\";
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the filename
|
// add the filename
|
||||||
_CompleteFilename += _Filename;
|
_CompleteFilename += _Filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SplitString(const std::string& str, const std::string& delim, std::vector<std::string>& output)
|
void SplitString(const std::string& str, const std::string& delim, std::vector<std::string>& output)
|
||||||
{
|
{
|
||||||
output.clear();
|
output.clear();
|
||||||
|
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
size_t delimIndex = 0;
|
size_t delimIndex = 0;
|
||||||
|
|
||||||
delimIndex = str.find(delim, offset);
|
delimIndex = str.find(delim, offset);
|
||||||
|
|
||||||
while (delimIndex != std::string::npos)
|
while (delimIndex != std::string::npos)
|
||||||
{
|
{
|
||||||
output.push_back(str.substr(offset, delimIndex - offset));
|
output.push_back(str.substr(offset, delimIndex - offset));
|
||||||
offset += delimIndex - offset + delim.length();
|
offset += delimIndex - offset + delim.length();
|
||||||
delimIndex = str.find(delim, offset);
|
delimIndex = str.find(delim, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
output.push_back(str.substr(offset));
|
output.push_back(str.substr(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TryParseUInt(const std::string& str, u32* output)
|
bool TryParseUInt(const std::string& str, u32* output)
|
||||||
{
|
{
|
||||||
if (!strcmp(str.substr(0, 2).c_str(), "0x") || !strcmp(str.substr(0, 2).c_str(), "0X"))
|
if (!strcmp(str.substr(0, 2).c_str(), "0x") || !strcmp(str.substr(0, 2).c_str(), "0X"))
|
||||||
return sscanf(str.c_str() + 2, "%x", output) > 0;
|
return sscanf(str.c_str() + 2, "%x", output) > 0;
|
||||||
else
|
else
|
||||||
return sscanf(str.c_str(), "%d", output) > 0;
|
return sscanf(str.c_str(), "%d", output) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ChooseStringFrom(const char* str, const char* * items)
|
int ChooseStringFrom(const char* str, const char* * items)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (items[i] != 0)
|
while (items[i] != 0)
|
||||||
{
|
{
|
||||||
if (!strcmp(str, items[i]))
|
if (!strcmp(str, items[i]))
|
||||||
return i;
|
return i;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Thousand separator. Turns 12345678 into 12,345,678.
|
// Thousand separator. Turns 12345678 into 12,345,678.
|
||||||
std::string ThS(int a, bool b)
|
std::string ThS(int a, bool b)
|
||||||
{
|
{
|
||||||
char cbuf[20];
|
char cbuf[20];
|
||||||
|
|
||||||
// determine treatment of signed or unsigned
|
// determine treatment of signed or unsigned
|
||||||
if(b) sprintf(cbuf, "%u", a); else sprintf(cbuf, "%i", a);
|
if(b) sprintf(cbuf, "%u", a); else sprintf(cbuf, "%i", a);
|
||||||
|
|
||||||
|
|
||||||
std::string sbuf = cbuf;
|
std::string sbuf = cbuf;
|
||||||
for (u32 i = 0; i < sbuf.length(); ++i)
|
for (u32 i = 0; i < sbuf.length(); ++i)
|
||||||
{
|
{
|
||||||
if((i & 3) == 3)
|
if((i & 3) == 3)
|
||||||
{
|
{
|
||||||
sbuf.insert(sbuf.length() - i, ",");
|
sbuf.insert(sbuf.length() - i, ",");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sbuf;
|
return sbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "TestFramework.h"
|
#include "TestFramework.h"
|
||||||
|
|
||||||
namespace __test
|
namespace __test
|
||||||
{
|
{
|
||||||
int numTests;
|
int numTests;
|
||||||
int numTestsFailed;
|
int numTestsFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int GetNumTests()
|
int GetNumTests()
|
||||||
{
|
{
|
||||||
return(__test::numTests);
|
return(__test::numTests);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int GetNumTestsFailed()
|
int GetNumTestsFailed()
|
||||||
{
|
{
|
||||||
return(__test::numTestsFailed);
|
return(__test::numTestsFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,404 +1,404 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#elif __GNUC__
|
#elif __GNUC__
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#else
|
#else
|
||||||
#error unsupported platform
|
#error unsupported platform
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
CriticalSection::CriticalSection(int spincount)
|
CriticalSection::CriticalSection(int spincount)
|
||||||
{
|
{
|
||||||
if (spincount)
|
if (spincount)
|
||||||
{
|
{
|
||||||
InitializeCriticalSectionAndSpinCount(§ion, spincount);
|
InitializeCriticalSectionAndSpinCount(§ion, spincount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InitializeCriticalSection(§ion);
|
InitializeCriticalSection(§ion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CriticalSection::~CriticalSection()
|
CriticalSection::~CriticalSection()
|
||||||
{
|
{
|
||||||
DeleteCriticalSection(§ion);
|
DeleteCriticalSection(§ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CriticalSection::Enter()
|
void CriticalSection::Enter()
|
||||||
{
|
{
|
||||||
EnterCriticalSection(§ion);
|
EnterCriticalSection(§ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CriticalSection::TryEnter()
|
bool CriticalSection::TryEnter()
|
||||||
{
|
{
|
||||||
return(TryEnterCriticalSection(§ion) ? true : false);
|
return(TryEnterCriticalSection(§ion) ? true : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CriticalSection::Leave()
|
void CriticalSection::Leave()
|
||||||
{
|
{
|
||||||
LeaveCriticalSection(§ion);
|
LeaveCriticalSection(§ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Thread::Thread(ThreadFunc function, void* arg)
|
Thread::Thread(ThreadFunc function, void* arg)
|
||||||
: m_hThread(NULL), m_threadId(0)
|
: m_hThread(NULL), m_threadId(0)
|
||||||
{
|
{
|
||||||
m_hThread = CreateThread(
|
m_hThread = CreateThread(
|
||||||
0, // Security attributes
|
0, // Security attributes
|
||||||
0, // Stack size
|
0, // Stack size
|
||||||
function,
|
function,
|
||||||
arg,
|
arg,
|
||||||
0,
|
0,
|
||||||
&m_threadId);
|
&m_threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Thread::~Thread()
|
Thread::~Thread()
|
||||||
{
|
{
|
||||||
WaitForDeath();
|
WaitForDeath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::WaitForDeath()
|
void Thread::WaitForDeath()
|
||||||
{
|
{
|
||||||
if (m_hThread)
|
if (m_hThread)
|
||||||
{
|
{
|
||||||
WaitForSingleObject(m_hThread, INFINITE);
|
WaitForSingleObject(m_hThread, INFINITE);
|
||||||
CloseHandle(m_hThread);
|
CloseHandle(m_hThread);
|
||||||
m_hThread = NULL;
|
m_hThread = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::SetAffinity(int mask)
|
void Thread::SetAffinity(int mask)
|
||||||
{
|
{
|
||||||
SetThreadAffinityMask(m_hThread, mask);
|
SetThreadAffinityMask(m_hThread, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::SetCurrentThreadAffinity(int mask)
|
void Thread::SetCurrentThreadAffinity(int mask)
|
||||||
{
|
{
|
||||||
SetThreadAffinityMask(GetCurrentThread(), mask);
|
SetThreadAffinityMask(GetCurrentThread(), mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Event::Event()
|
Event::Event()
|
||||||
{
|
{
|
||||||
m_hEvent = 0;
|
m_hEvent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Event::Init()
|
void Event::Init()
|
||||||
{
|
{
|
||||||
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Event::Shutdown()
|
void Event::Shutdown()
|
||||||
{
|
{
|
||||||
CloseHandle(m_hEvent);
|
CloseHandle(m_hEvent);
|
||||||
m_hEvent = 0;
|
m_hEvent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Event::Set()
|
void Event::Set()
|
||||||
{
|
{
|
||||||
SetEvent(m_hEvent);
|
SetEvent(m_hEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Event::Wait()
|
void Event::Wait()
|
||||||
{
|
{
|
||||||
WaitForSingleObject(m_hEvent, INFINITE);
|
WaitForSingleObject(m_hEvent, INFINITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SleepCurrentThread(int ms)
|
void SleepCurrentThread(int ms)
|
||||||
{
|
{
|
||||||
Sleep(ms);
|
Sleep(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct tagTHREADNAME_INFO
|
typedef struct tagTHREADNAME_INFO
|
||||||
{
|
{
|
||||||
DWORD dwType; // must be 0x1000
|
DWORD dwType; // must be 0x1000
|
||||||
LPCSTR szName; // pointer to name (in user addr space)
|
LPCSTR szName; // pointer to name (in user addr space)
|
||||||
DWORD dwThreadID; // thread ID (-1=caller thread)
|
DWORD dwThreadID; // thread ID (-1=caller thread)
|
||||||
DWORD dwFlags; // reserved for future use, must be zero
|
DWORD dwFlags; // reserved for future use, must be zero
|
||||||
} THREADNAME_INFO;
|
} THREADNAME_INFO;
|
||||||
// Usage: SetThreadName (-1, "MainThread");
|
// Usage: SetThreadName (-1, "MainThread");
|
||||||
//
|
//
|
||||||
// Sets the debugger-visible name of the current thread.
|
// Sets the debugger-visible name of the current thread.
|
||||||
// Uses undocumented (actually, it is now documented) trick.
|
// Uses undocumented (actually, it is now documented) trick.
|
||||||
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
|
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
|
||||||
|
|
||||||
void SetCurrentThreadName(const TCHAR* szThreadName)
|
void SetCurrentThreadName(const TCHAR* szThreadName)
|
||||||
{
|
{
|
||||||
THREADNAME_INFO info;
|
THREADNAME_INFO info;
|
||||||
info.dwType = 0x1000;
|
info.dwType = 0x1000;
|
||||||
#ifdef UNICODE
|
#ifdef UNICODE
|
||||||
//TODO: Find the proper way to do this.
|
//TODO: Find the proper way to do this.
|
||||||
char tname[256];
|
char tname[256];
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < _tcslen(szThreadName); i++)
|
for (i = 0; i < _tcslen(szThreadName); i++)
|
||||||
{
|
{
|
||||||
tname[i] = (char)szThreadName[i]; //poor man's unicode->ansi, TODO: fix
|
tname[i] = (char)szThreadName[i]; //poor man's unicode->ansi, TODO: fix
|
||||||
}
|
}
|
||||||
|
|
||||||
tname[i] = 0;
|
tname[i] = 0;
|
||||||
info.szName = tname;
|
info.szName = tname;
|
||||||
#else
|
#else
|
||||||
info.szName = szThreadName;
|
info.szName = szThreadName;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
info.dwThreadID = -1; //dwThreadID;
|
info.dwThreadID = -1; //dwThreadID;
|
||||||
info.dwFlags = 0;
|
info.dwFlags = 0;
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR*)&info);
|
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR*)&info);
|
||||||
}
|
}
|
||||||
__except(EXCEPTION_CONTINUE_EXECUTION)
|
__except(EXCEPTION_CONTINUE_EXECUTION)
|
||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
// TODO: check if ever inline
|
// TODO: check if ever inline
|
||||||
LONG SyncInterlockedIncrement(LONG *Dest)
|
LONG SyncInterlockedIncrement(LONG *Dest)
|
||||||
{
|
{
|
||||||
return InterlockedIncrement(Dest);
|
return InterlockedIncrement(Dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val)
|
LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val)
|
||||||
{
|
{
|
||||||
return InterlockedExchangeAdd(Dest, Val);
|
return InterlockedExchangeAdd(Dest, Val);
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
|
LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
|
||||||
{
|
{
|
||||||
return InterlockedExchange(Dest, Val);
|
return InterlockedExchange(Dest, Val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif __GNUC__
|
#elif __GNUC__
|
||||||
CriticalSection::CriticalSection(int spincount_unused)
|
CriticalSection::CriticalSection(int spincount_unused)
|
||||||
{
|
{
|
||||||
pthread_mutex_init(&mutex, 0);
|
pthread_mutex_init(&mutex, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CriticalSection::~CriticalSection()
|
CriticalSection::~CriticalSection()
|
||||||
{
|
{
|
||||||
pthread_mutex_destroy(&mutex);
|
pthread_mutex_destroy(&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CriticalSection::Enter()
|
void CriticalSection::Enter()
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&mutex);
|
pthread_mutex_lock(&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CriticalSection::TryEnter()
|
bool CriticalSection::TryEnter()
|
||||||
{
|
{
|
||||||
return(!pthread_mutex_trylock(&mutex));
|
return(!pthread_mutex_trylock(&mutex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CriticalSection::Leave()
|
void CriticalSection::Leave()
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(&mutex);
|
pthread_mutex_unlock(&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Thread::Thread(ThreadFunc function, void* arg)
|
Thread::Thread(ThreadFunc function, void* arg)
|
||||||
: thread_id(0)
|
: thread_id(0)
|
||||||
{
|
{
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
pthread_attr_setstacksize(&attr, 1024 * 1024);
|
pthread_attr_setstacksize(&attr, 1024 * 1024);
|
||||||
pthread_create(&thread_id, &attr, function, arg);
|
pthread_create(&thread_id, &attr, function, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Thread::~Thread()
|
Thread::~Thread()
|
||||||
{
|
{
|
||||||
WaitForDeath();
|
WaitForDeath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::WaitForDeath()
|
void Thread::WaitForDeath()
|
||||||
{
|
{
|
||||||
if (thread_id)
|
if (thread_id)
|
||||||
{
|
{
|
||||||
void* exit_status;
|
void* exit_status;
|
||||||
pthread_join(thread_id, &exit_status);
|
pthread_join(thread_id, &exit_status);
|
||||||
if (exit_status)
|
if (exit_status)
|
||||||
fprintf(stderr, "error %d joining thread\n", *(int *)exit_status);
|
fprintf(stderr, "error %d joining thread\n", *(int *)exit_status);
|
||||||
thread_id = 0;
|
thread_id = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::SetAffinity(int mask)
|
void Thread::SetAffinity(int mask)
|
||||||
{
|
{
|
||||||
// This is non-standard
|
// This is non-standard
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
cpu_set_t cpu_set;
|
cpu_set_t cpu_set;
|
||||||
CPU_ZERO(&cpu_set);
|
CPU_ZERO(&cpu_set);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < sizeof(mask) * 8; i++)
|
for (unsigned int i = 0; i < sizeof(mask) * 8; i++)
|
||||||
{
|
{
|
||||||
if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
|
if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_setaffinity_np(thread_id, sizeof(cpu_set), &cpu_set);
|
pthread_setaffinity_np(thread_id, sizeof(cpu_set), &cpu_set);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::SetCurrentThreadAffinity(int mask)
|
void Thread::SetCurrentThreadAffinity(int mask)
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
cpu_set_t cpu_set;
|
cpu_set_t cpu_set;
|
||||||
CPU_ZERO(&cpu_set);
|
CPU_ZERO(&cpu_set);
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(mask) * 8; i++)
|
for (size_t i = 0; i < sizeof(mask) * 8; i++)
|
||||||
{
|
{
|
||||||
if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
|
if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
|
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SleepCurrentThread(int ms)
|
void SleepCurrentThread(int ms)
|
||||||
{
|
{
|
||||||
usleep(1000 * ms);
|
usleep(1000 * ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SetCurrentThreadName(const TCHAR* szThreadName)
|
void SetCurrentThreadName(const TCHAR* szThreadName)
|
||||||
{
|
{
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Event::Event()
|
Event::Event()
|
||||||
{
|
{
|
||||||
is_set_ = false;
|
is_set_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Event::Init()
|
void Event::Init()
|
||||||
{
|
{
|
||||||
pthread_cond_init(&event_, 0);
|
pthread_cond_init(&event_, 0);
|
||||||
pthread_mutex_init(&mutex_, 0);
|
pthread_mutex_init(&mutex_, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Event::Shutdown()
|
void Event::Shutdown()
|
||||||
{
|
{
|
||||||
pthread_mutex_destroy(&mutex_);
|
pthread_mutex_destroy(&mutex_);
|
||||||
pthread_cond_destroy(&event_);
|
pthread_cond_destroy(&event_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Event::Set()
|
void Event::Set()
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&mutex_);
|
pthread_mutex_lock(&mutex_);
|
||||||
|
|
||||||
if (!is_set_)
|
if (!is_set_)
|
||||||
{
|
{
|
||||||
is_set_ = true;
|
is_set_ = true;
|
||||||
pthread_cond_signal(&event_);
|
pthread_cond_signal(&event_);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&mutex_);
|
pthread_mutex_unlock(&mutex_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Event::Wait()
|
void Event::Wait()
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&mutex_);
|
pthread_mutex_lock(&mutex_);
|
||||||
|
|
||||||
while (!is_set_)
|
while (!is_set_)
|
||||||
{
|
{
|
||||||
pthread_cond_wait(&event_, &mutex_);
|
pthread_cond_wait(&event_, &mutex_);
|
||||||
}
|
}
|
||||||
|
|
||||||
is_set_ = false;
|
is_set_ = false;
|
||||||
pthread_mutex_unlock(&mutex_);
|
pthread_mutex_unlock(&mutex_);
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG SyncInterlockedIncrement(LONG *Dest)
|
LONG SyncInterlockedIncrement(LONG *Dest)
|
||||||
{
|
{
|
||||||
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
|
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
|
||||||
return __sync_add_and_fetch(Dest, 1);
|
return __sync_add_and_fetch(Dest, 1);
|
||||||
#else
|
#else
|
||||||
register int result;
|
register int result;
|
||||||
__asm__ __volatile__("lock; xadd %0,%1"
|
__asm__ __volatile__("lock; xadd %0,%1"
|
||||||
: "=r" (result), "=m" (*Dest)
|
: "=r" (result), "=m" (*Dest)
|
||||||
: "0" (1), "m" (*Dest)
|
: "0" (1), "m" (*Dest)
|
||||||
: "memory");
|
: "memory");
|
||||||
return result;
|
return result;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val)
|
LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val)
|
||||||
{
|
{
|
||||||
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
|
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
|
||||||
return __sync_add_and_fetch(Dest, Val);
|
return __sync_add_and_fetch(Dest, Val);
|
||||||
#else
|
#else
|
||||||
register int result;
|
register int result;
|
||||||
__asm__ __volatile__("lock; xadd %0,%1"
|
__asm__ __volatile__("lock; xadd %0,%1"
|
||||||
: "=r" (result), "=m" (*Dest)
|
: "=r" (result), "=m" (*Dest)
|
||||||
: "0" (Val), "m" (*Dest)
|
: "0" (Val), "m" (*Dest)
|
||||||
: "memory");
|
: "memory");
|
||||||
return result;
|
return result;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
|
LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
|
||||||
{
|
{
|
||||||
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
|
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
|
||||||
return __sync_lock_test_and_set(Dest, Val);
|
return __sync_lock_test_and_set(Dest, Val);
|
||||||
#else
|
#else
|
||||||
register int result;
|
register int result;
|
||||||
__asm__ __volatile__("lock; xchg %0,%1"
|
__asm__ __volatile__("lock; xchg %0,%1"
|
||||||
: "=r" (result), "=m" (*Dest)
|
: "=r" (result), "=m" (*Dest)
|
||||||
: "0" (Val), "m" (*Dest)
|
: "0" (Val), "m" (*Dest)
|
||||||
: "memory");
|
: "memory");
|
||||||
return result;
|
return result;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // end of namespace Common
|
} // end of namespace Common
|
||||||
|
|
|
@ -1,153 +1,153 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Thunk.h"
|
#include "Thunk.h"
|
||||||
#include "x64Emitter.h"
|
#include "x64Emitter.h"
|
||||||
#include "MemoryUtil.h"
|
#include "MemoryUtil.h"
|
||||||
#include "ABI.h"
|
#include "ABI.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
#define THUNK_ARENA_SIZE 1024*1024*1
|
#define THUNK_ARENA_SIZE 1024*1024*1
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static std::map<void *, const u8 *> thunks;
|
static std::map<void *, const u8 *> thunks;
|
||||||
u8 GC_ALIGNED32(saved_fp_state[16 * 4 * 4]);
|
u8 GC_ALIGNED32(saved_fp_state[16 * 4 * 4]);
|
||||||
u8 GC_ALIGNED32(saved_gpr_state[16 * 8]);
|
u8 GC_ALIGNED32(saved_gpr_state[16 * 8]);
|
||||||
|
|
||||||
static u8 *thunk_memory;
|
static u8 *thunk_memory;
|
||||||
static u8 *thunk_code;
|
static u8 *thunk_code;
|
||||||
static const u8 *save_regs;
|
static const u8 *save_regs;
|
||||||
static const u8 *load_regs;
|
static const u8 *load_regs;
|
||||||
static u16 saved_mxcsr;
|
static u16 saved_mxcsr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thunk_Init()
|
void Thunk_Init()
|
||||||
{
|
{
|
||||||
thunk_memory = (u8 *)AllocateExecutableMemory(THUNK_ARENA_SIZE);
|
thunk_memory = (u8 *)AllocateExecutableMemory(THUNK_ARENA_SIZE);
|
||||||
thunk_code = thunk_memory;
|
thunk_code = thunk_memory;
|
||||||
|
|
||||||
GenContext ctx(&thunk_code);
|
GenContext ctx(&thunk_code);
|
||||||
save_regs = GetCodePtr();
|
save_regs = GetCodePtr();
|
||||||
for (int i = 2; i < ABI_GetNumXMMRegs(); i++)
|
for (int i = 2; i < ABI_GetNumXMMRegs(); i++)
|
||||||
MOVAPS(M(saved_fp_state + i * 16), (X64Reg)(XMM0 + i));
|
MOVAPS(M(saved_fp_state + i * 16), (X64Reg)(XMM0 + i));
|
||||||
STMXCSR(M(&saved_mxcsr));
|
STMXCSR(M(&saved_mxcsr));
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
MOV(64, M(saved_gpr_state + 0 ), R(RCX));
|
MOV(64, M(saved_gpr_state + 0 ), R(RCX));
|
||||||
MOV(64, M(saved_gpr_state + 8 ), R(RDX));
|
MOV(64, M(saved_gpr_state + 8 ), R(RDX));
|
||||||
MOV(64, M(saved_gpr_state + 16), R(R8) );
|
MOV(64, M(saved_gpr_state + 16), R(R8) );
|
||||||
MOV(64, M(saved_gpr_state + 24), R(R9) );
|
MOV(64, M(saved_gpr_state + 24), R(R9) );
|
||||||
MOV(64, M(saved_gpr_state + 32), R(R10));
|
MOV(64, M(saved_gpr_state + 32), R(R10));
|
||||||
MOV(64, M(saved_gpr_state + 40), R(R11));
|
MOV(64, M(saved_gpr_state + 40), R(R11));
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
MOV(64, M(saved_gpr_state + 48), R(RSI));
|
MOV(64, M(saved_gpr_state + 48), R(RSI));
|
||||||
MOV(64, M(saved_gpr_state + 56), R(RDI));
|
MOV(64, M(saved_gpr_state + 56), R(RDI));
|
||||||
#endif
|
#endif
|
||||||
MOV(64, M(saved_gpr_state + 64), R(RBX));
|
MOV(64, M(saved_gpr_state + 64), R(RBX));
|
||||||
#else
|
#else
|
||||||
MOV(32, M(saved_gpr_state + 0 ), R(RCX));
|
MOV(32, M(saved_gpr_state + 0 ), R(RCX));
|
||||||
MOV(32, M(saved_gpr_state + 4 ), R(RDX));
|
MOV(32, M(saved_gpr_state + 4 ), R(RDX));
|
||||||
#endif
|
#endif
|
||||||
RET();
|
RET();
|
||||||
load_regs = GetCodePtr();
|
load_regs = GetCodePtr();
|
||||||
LDMXCSR(M(&saved_mxcsr));
|
LDMXCSR(M(&saved_mxcsr));
|
||||||
for (int i = 2; i < ABI_GetNumXMMRegs(); i++)
|
for (int i = 2; i < ABI_GetNumXMMRegs(); i++)
|
||||||
MOVAPS((X64Reg)(XMM0 + i), M(saved_fp_state + i * 16));
|
MOVAPS((X64Reg)(XMM0 + i), M(saved_fp_state + i * 16));
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
MOV(64, R(RCX), M(saved_gpr_state + 0 ));
|
MOV(64, R(RCX), M(saved_gpr_state + 0 ));
|
||||||
MOV(64, R(RDX), M(saved_gpr_state + 8 ));
|
MOV(64, R(RDX), M(saved_gpr_state + 8 ));
|
||||||
MOV(64, R(R8) , M(saved_gpr_state + 16));
|
MOV(64, R(R8) , M(saved_gpr_state + 16));
|
||||||
MOV(64, R(R9) , M(saved_gpr_state + 24));
|
MOV(64, R(R9) , M(saved_gpr_state + 24));
|
||||||
MOV(64, R(R10), M(saved_gpr_state + 32));
|
MOV(64, R(R10), M(saved_gpr_state + 32));
|
||||||
MOV(64, R(R11), M(saved_gpr_state + 40));
|
MOV(64, R(R11), M(saved_gpr_state + 40));
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
MOV(64, R(RSI), M(saved_gpr_state + 48));
|
MOV(64, R(RSI), M(saved_gpr_state + 48));
|
||||||
MOV(64, R(RDI), M(saved_gpr_state + 56));
|
MOV(64, R(RDI), M(saved_gpr_state + 56));
|
||||||
#endif
|
#endif
|
||||||
MOV(64, R(RBX), M(saved_gpr_state + 64));
|
MOV(64, R(RBX), M(saved_gpr_state + 64));
|
||||||
#else
|
#else
|
||||||
MOV(32, R(RCX), M(saved_gpr_state + 0 ));
|
MOV(32, R(RCX), M(saved_gpr_state + 0 ));
|
||||||
MOV(32, R(RDX), M(saved_gpr_state + 4 ));
|
MOV(32, R(RDX), M(saved_gpr_state + 4 ));
|
||||||
#endif
|
#endif
|
||||||
RET();
|
RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thunk_Reset()
|
void Thunk_Reset()
|
||||||
{
|
{
|
||||||
thunks.clear();
|
thunks.clear();
|
||||||
thunk_code = thunk_memory;
|
thunk_code = thunk_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thunk_Shutdown()
|
void Thunk_Shutdown()
|
||||||
{
|
{
|
||||||
Thunk_Reset();
|
Thunk_Reset();
|
||||||
FreeMemoryPages(thunk_memory, THUNK_ARENA_SIZE);
|
FreeMemoryPages(thunk_memory, THUNK_ARENA_SIZE);
|
||||||
thunk_memory = 0;
|
thunk_memory = 0;
|
||||||
thunk_code = 0;
|
thunk_code = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ProtectFunction(void *function, int num_params)
|
void *ProtectFunction(void *function, int num_params)
|
||||||
{
|
{
|
||||||
std::map<void *, const u8 *>::iterator iter;
|
std::map<void *, const u8 *>::iterator iter;
|
||||||
iter = thunks.find(function);
|
iter = thunks.find(function);
|
||||||
if (iter != thunks.end())
|
if (iter != thunks.end())
|
||||||
return (void *)iter->second;
|
return (void *)iter->second;
|
||||||
|
|
||||||
if (!thunk_memory)
|
if (!thunk_memory)
|
||||||
PanicAlert("Trying to protect functions before the emu is started. Bad bad bad.");
|
PanicAlert("Trying to protect functions before the emu is started. Bad bad bad.");
|
||||||
|
|
||||||
GenContext gen(&thunk_code);
|
GenContext gen(&thunk_code);
|
||||||
const u8 *call_point = GetCodePtr();
|
const u8 *call_point = GetCodePtr();
|
||||||
// Make sure to align stack.
|
// Make sure to align stack.
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SUB(64, R(ESP), Imm8(0x28));
|
SUB(64, R(ESP), Imm8(0x28));
|
||||||
#else
|
#else
|
||||||
SUB(64, R(ESP), Imm8(0x8));
|
SUB(64, R(ESP), Imm8(0x8));
|
||||||
#endif
|
#endif
|
||||||
CALL((void*)save_regs);
|
CALL((void*)save_regs);
|
||||||
CALL((void*)function);
|
CALL((void*)function);
|
||||||
CALL((void*)load_regs);
|
CALL((void*)load_regs);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ADD(64, R(ESP), Imm8(0x28));
|
ADD(64, R(ESP), Imm8(0x28));
|
||||||
#else
|
#else
|
||||||
ADD(64, R(ESP), Imm8(0x8));
|
ADD(64, R(ESP), Imm8(0x8));
|
||||||
#endif
|
#endif
|
||||||
RET();
|
RET();
|
||||||
#else
|
#else
|
||||||
CALL((void*)save_regs);
|
CALL((void*)save_regs);
|
||||||
// Since parameters are in the previous stack frame, not in registers, this takes some
|
// Since parameters are in the previous stack frame, not in registers, this takes some
|
||||||
// trickery : we simply re-push the parameters. might not be optimal, but that doesn't really
|
// trickery : we simply re-push the parameters. might not be optimal, but that doesn't really
|
||||||
// matter.
|
// matter.
|
||||||
ABI_AlignStack(num_params * 4);
|
ABI_AlignStack(num_params * 4);
|
||||||
unsigned int alignedSize = ABI_GetAlignedFrameSize(num_params * 4);
|
unsigned int alignedSize = ABI_GetAlignedFrameSize(num_params * 4);
|
||||||
for (int i = 0; i < num_params; i++) {
|
for (int i = 0; i < num_params; i++) {
|
||||||
// ESP is changing, so we do not need i
|
// ESP is changing, so we do not need i
|
||||||
PUSH(32, MDisp(ESP, alignedSize - 4));
|
PUSH(32, MDisp(ESP, alignedSize - 4));
|
||||||
}
|
}
|
||||||
CALL(function);
|
CALL(function);
|
||||||
ABI_RestoreStack(num_params * 4);
|
ABI_RestoreStack(num_params * 4);
|
||||||
CALL((void*)load_regs);
|
CALL((void*)load_regs);
|
||||||
RET();
|
RET();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
thunks[function] = call_point;
|
thunks[function] = call_point;
|
||||||
return (void *)call_point;
|
return (void *)call_point;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,99 +1,99 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <mmsystem.h>
|
#include <mmsystem.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#include <sys/timeb.h>
|
#include <sys/timeb.h>
|
||||||
|
|
||||||
u32 timeGetTime()
|
u32 timeGetTime()
|
||||||
{
|
{
|
||||||
struct timeb t;
|
struct timeb t;
|
||||||
ftime(&t);
|
ftime(&t);
|
||||||
return((u32)(t.time * 1000 + t.millitm));
|
return((u32)(t.time * 1000 + t.millitm));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
Timer::Timer(void)
|
Timer::Timer(void)
|
||||||
: m_LastTime(0)
|
: m_LastTime(0)
|
||||||
{
|
{
|
||||||
Update();
|
Update();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
QueryPerformanceFrequency((LARGE_INTEGER*)&m_frequency);
|
QueryPerformanceFrequency((LARGE_INTEGER*)&m_frequency);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Timer::Update(void)
|
void Timer::Update(void)
|
||||||
{
|
{
|
||||||
m_LastTime = timeGetTime();
|
m_LastTime = timeGetTime();
|
||||||
//TODO(ector) - QPF
|
//TODO(ector) - QPF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
s64 Timer::GetTimeDifference(void)
|
s64 Timer::GetTimeDifference(void)
|
||||||
{
|
{
|
||||||
return(timeGetTime() - m_LastTime);
|
return(timeGetTime() - m_LastTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Timer::IncreaseResolution()
|
void Timer::IncreaseResolution()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
timeBeginPeriod(1);
|
timeBeginPeriod(1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Timer::RestoreResolution()
|
void Timer::RestoreResolution()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
timeEndPeriod(1);
|
timeEndPeriod(1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
void _time64(u64* t)
|
void _time64(u64* t)
|
||||||
{
|
{
|
||||||
*t = 0; //TODO
|
*t = 0; //TODO
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
u64 Timer::GetTimeSinceJan1970(void)
|
u64 Timer::GetTimeSinceJan1970(void)
|
||||||
{
|
{
|
||||||
time_t ltime;
|
time_t ltime;
|
||||||
time(<ime);
|
time(<ime);
|
||||||
return((u64)ltime);
|
return((u64)ltime);
|
||||||
}
|
}
|
||||||
} // end of namespace Common
|
} // end of namespace Common
|
||||||
|
|
|
@ -1,123 +1,123 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "WaveFile.h"
|
#include "WaveFile.h"
|
||||||
|
|
||||||
enum {BUF_SIZE = 32*1024};
|
enum {BUF_SIZE = 32*1024};
|
||||||
|
|
||||||
WaveFileWriter::WaveFileWriter()
|
WaveFileWriter::WaveFileWriter()
|
||||||
{
|
{
|
||||||
conv_buffer = 0;
|
conv_buffer = 0;
|
||||||
skip_silence = false;
|
skip_silence = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaveFileWriter::~WaveFileWriter()
|
WaveFileWriter::~WaveFileWriter()
|
||||||
{
|
{
|
||||||
delete [] conv_buffer;
|
delete [] conv_buffer;
|
||||||
Stop();
|
Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WaveFileWriter::Start(const char *filename)
|
bool WaveFileWriter::Start(const char *filename)
|
||||||
{
|
{
|
||||||
if (!conv_buffer)
|
if (!conv_buffer)
|
||||||
conv_buffer = new short[BUF_SIZE];
|
conv_buffer = new short[BUF_SIZE];
|
||||||
|
|
||||||
if (file)
|
if (file)
|
||||||
return false;
|
return false;
|
||||||
file = fopen(filename, "wb");
|
file = fopen(filename, "wb");
|
||||||
if (!file)
|
if (!file)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Write4("RIFF");
|
Write4("RIFF");
|
||||||
Write(100 * 1000 * 1000); // write big value in case the file gets truncated
|
Write(100 * 1000 * 1000); // write big value in case the file gets truncated
|
||||||
Write4("WAVE");
|
Write4("WAVE");
|
||||||
Write4("fmt ");
|
Write4("fmt ");
|
||||||
Write(16); // size of fmt block
|
Write(16); // size of fmt block
|
||||||
Write(0x00020001); //two channels, uncompressed
|
Write(0x00020001); //two channels, uncompressed
|
||||||
const u32 sample_rate = 32000;
|
const u32 sample_rate = 32000;
|
||||||
Write(sample_rate);
|
Write(sample_rate);
|
||||||
Write(sample_rate * 2 * 2); //two channels, 16bit
|
Write(sample_rate * 2 * 2); //two channels, 16bit
|
||||||
Write(0x00100004);
|
Write(0x00100004);
|
||||||
Write4("data");
|
Write4("data");
|
||||||
Write(100 * 1000 * 1000 - 32);
|
Write(100 * 1000 * 1000 - 32);
|
||||||
// We are now at offset 44
|
// We are now at offset 44
|
||||||
if (ftell(file) != 44)
|
if (ftell(file) != 44)
|
||||||
PanicAlert("wrong offset: %i", ftell(file));
|
PanicAlert("wrong offset: %i", ftell(file));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaveFileWriter::Stop()
|
void WaveFileWriter::Stop()
|
||||||
{
|
{
|
||||||
if (!file)
|
if (!file)
|
||||||
return;
|
return;
|
||||||
// u32 file_size = (u32)ftell(file);
|
// u32 file_size = (u32)ftell(file);
|
||||||
fseek(file, 4, SEEK_SET);
|
fseek(file, 4, SEEK_SET);
|
||||||
Write(audio_size + 36);
|
Write(audio_size + 36);
|
||||||
fseek(file, 40, SEEK_SET);
|
fseek(file, 40, SEEK_SET);
|
||||||
Write(audio_size);
|
Write(audio_size);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
file = 0;
|
file = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaveFileWriter::Write(u32 value)
|
void WaveFileWriter::Write(u32 value)
|
||||||
{
|
{
|
||||||
fwrite(&value, 4, 1, file);
|
fwrite(&value, 4, 1, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaveFileWriter::Write4(const char *ptr)
|
void WaveFileWriter::Write4(const char *ptr)
|
||||||
{
|
{
|
||||||
fwrite(ptr, 4, 1, file);
|
fwrite(ptr, 4, 1, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaveFileWriter::AddStereoSamples(const short *sample_data, int count)
|
void WaveFileWriter::AddStereoSamples(const short *sample_data, int count)
|
||||||
{
|
{
|
||||||
if (!file)
|
if (!file)
|
||||||
PanicAlert("WaveFileWriter - file not open.");
|
PanicAlert("WaveFileWriter - file not open.");
|
||||||
if (skip_silence) {
|
if (skip_silence) {
|
||||||
bool all_zero = true;
|
bool all_zero = true;
|
||||||
for (int i = 0; i < count * 2; i++)
|
for (int i = 0; i < count * 2; i++)
|
||||||
if (sample_data[i])
|
if (sample_data[i])
|
||||||
all_zero = false;
|
all_zero = false;
|
||||||
if (all_zero)
|
if (all_zero)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fwrite(sample_data, count * 4, 1, file);
|
fwrite(sample_data, count * 4, 1, file);
|
||||||
audio_size += count * 4;
|
audio_size += count * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaveFileWriter::AddStereoSamplesBE(const short *sample_data, int count)
|
void WaveFileWriter::AddStereoSamplesBE(const short *sample_data, int count)
|
||||||
{
|
{
|
||||||
if (!file)
|
if (!file)
|
||||||
PanicAlert("WaveFileWriter - file not open.");
|
PanicAlert("WaveFileWriter - file not open.");
|
||||||
if (count > BUF_SIZE * 2)
|
if (count > BUF_SIZE * 2)
|
||||||
PanicAlert("WaveFileWriter - buffer too small (count = %i).", count);
|
PanicAlert("WaveFileWriter - buffer too small (count = %i).", count);
|
||||||
if (skip_silence) {
|
if (skip_silence) {
|
||||||
bool all_zero = true;
|
bool all_zero = true;
|
||||||
for (int i = 0; i < count * 2; i++)
|
for (int i = 0; i < count * 2; i++)
|
||||||
if (sample_data[i])
|
if (sample_data[i])
|
||||||
all_zero = false;
|
all_zero = false;
|
||||||
if (all_zero)
|
if (all_zero)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < count * 2; i++) {
|
for (int i = 0; i < count * 2; i++) {
|
||||||
conv_buffer[i] = Common::swap16((u16)sample_data[i]);
|
conv_buffer[i] = Common::swap16((u16)sample_data[i]);
|
||||||
}
|
}
|
||||||
fwrite(conv_buffer, count * 4, 1, file);
|
fwrite(conv_buffer, count * 4, 1, file);
|
||||||
audio_size += count * 4;
|
audio_size += count * 4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
|
|
@ -1,232 +1,232 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
#include "x64Analyzer.h"
|
#include "x64Analyzer.h"
|
||||||
|
|
||||||
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType)
|
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType)
|
||||||
{
|
{
|
||||||
unsigned const char *startCodePtr = codePtr;
|
unsigned const char *startCodePtr = codePtr;
|
||||||
u8 rex = 0;
|
u8 rex = 0;
|
||||||
u8 codeByte = 0;
|
u8 codeByte = 0;
|
||||||
u8 codeByte2 = 0;
|
u8 codeByte2 = 0;
|
||||||
|
|
||||||
//Check for regular prefix
|
//Check for regular prefix
|
||||||
info.operandSize = 4;
|
info.operandSize = 4;
|
||||||
info.zeroExtend = false;
|
info.zeroExtend = false;
|
||||||
info.signExtend = false;
|
info.signExtend = false;
|
||||||
info.hasImmediate = false;
|
info.hasImmediate = false;
|
||||||
info.isMemoryWrite = false;
|
info.isMemoryWrite = false;
|
||||||
|
|
||||||
int addressSize = 8;
|
int addressSize = 8;
|
||||||
u8 modRMbyte = 0;
|
u8 modRMbyte = 0;
|
||||||
u8 sibByte = 0;
|
u8 sibByte = 0;
|
||||||
bool hasModRM = false;
|
bool hasModRM = false;
|
||||||
bool hasSIBbyte = false;
|
bool hasSIBbyte = false;
|
||||||
bool hasDisplacement = false;
|
bool hasDisplacement = false;
|
||||||
|
|
||||||
int displacementSize = 0;
|
int displacementSize = 0;
|
||||||
|
|
||||||
if (*codePtr == 0x66)
|
if (*codePtr == 0x66)
|
||||||
{
|
{
|
||||||
info.operandSize = 2;
|
info.operandSize = 2;
|
||||||
codePtr++;
|
codePtr++;
|
||||||
}
|
}
|
||||||
else if (*codePtr == 0x67)
|
else if (*codePtr == 0x67)
|
||||||
{
|
{
|
||||||
addressSize = 4;
|
addressSize = 4;
|
||||||
codePtr++;
|
codePtr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check for REX prefix
|
//Check for REX prefix
|
||||||
if ((*codePtr & 0xF0) == 0x40)
|
if ((*codePtr & 0xF0) == 0x40)
|
||||||
{
|
{
|
||||||
rex = *codePtr;
|
rex = *codePtr;
|
||||||
if (rex & 8) //REX.W
|
if (rex & 8) //REX.W
|
||||||
{
|
{
|
||||||
info.operandSize = 8;
|
info.operandSize = 8;
|
||||||
}
|
}
|
||||||
codePtr++;
|
codePtr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
codeByte = *codePtr++;
|
codeByte = *codePtr++;
|
||||||
|
|
||||||
// Skip two-byte opcode byte
|
// Skip two-byte opcode byte
|
||||||
bool twoByte = false;
|
bool twoByte = false;
|
||||||
if(codeByte == 0x0F)
|
if(codeByte == 0x0F)
|
||||||
{
|
{
|
||||||
twoByte = true;
|
twoByte = true;
|
||||||
codeByte2 = *codePtr++;
|
codeByte2 = *codePtr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!twoByte)
|
if (!twoByte)
|
||||||
{
|
{
|
||||||
if ((codeByte & 0xF0) == 0x80 ||
|
if ((codeByte & 0xF0) == 0x80 ||
|
||||||
((codeByte & 0xF8) == 0xC0 && (codeByte & 0x0E) != 0x02))
|
((codeByte & 0xF8) == 0xC0 && (codeByte & 0x0E) != 0x02))
|
||||||
{
|
{
|
||||||
modRMbyte = *codePtr++;
|
modRMbyte = *codePtr++;
|
||||||
hasModRM = true;
|
hasModRM = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (((codeByte2 & 0xF0) == 0x00 && (codeByte2 & 0x0F) >= 0x04 && (codeByte2 & 0x0D) != 0x0D) ||
|
if (((codeByte2 & 0xF0) == 0x00 && (codeByte2 & 0x0F) >= 0x04 && (codeByte2 & 0x0D) != 0x0D) ||
|
||||||
(codeByte2 & 0xF0) == 0x30 ||
|
(codeByte2 & 0xF0) == 0x30 ||
|
||||||
codeByte2 == 0x77 ||
|
codeByte2 == 0x77 ||
|
||||||
(codeByte2 & 0xF0) == 0x80 ||
|
(codeByte2 & 0xF0) == 0x80 ||
|
||||||
((codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02) ||
|
((codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02) ||
|
||||||
(codeByte2 & 0xF8) == 0xC8)
|
(codeByte2 & 0xF8) == 0xC8)
|
||||||
{
|
{
|
||||||
// No mod R/M byte
|
// No mod R/M byte
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
modRMbyte = *codePtr++;
|
modRMbyte = *codePtr++;
|
||||||
hasModRM = true;
|
hasModRM = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasModRM)
|
if (hasModRM)
|
||||||
{
|
{
|
||||||
ModRM mrm(modRMbyte, rex);
|
ModRM mrm(modRMbyte, rex);
|
||||||
info.regOperandReg = mrm.reg;
|
info.regOperandReg = mrm.reg;
|
||||||
if (mrm.mod < 3)
|
if (mrm.mod < 3)
|
||||||
{
|
{
|
||||||
if (mrm.rm == 4)
|
if (mrm.rm == 4)
|
||||||
{
|
{
|
||||||
//SIB byte
|
//SIB byte
|
||||||
sibByte = *codePtr++;
|
sibByte = *codePtr++;
|
||||||
info.scaledReg = (sibByte >> 3) & 7;
|
info.scaledReg = (sibByte >> 3) & 7;
|
||||||
info.otherReg = (sibByte & 7);
|
info.otherReg = (sibByte & 7);
|
||||||
if (rex & 2) info.scaledReg += 8;
|
if (rex & 2) info.scaledReg += 8;
|
||||||
if (rex & 1) info.otherReg += 8;
|
if (rex & 1) info.otherReg += 8;
|
||||||
hasSIBbyte = true;
|
hasSIBbyte = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//info.scaledReg =
|
//info.scaledReg =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mrm.mod == 1 || mrm.mod == 2)
|
if (mrm.mod == 1 || mrm.mod == 2)
|
||||||
{
|
{
|
||||||
hasDisplacement = true;
|
hasDisplacement = true;
|
||||||
if (mrm.mod == 1)
|
if (mrm.mod == 1)
|
||||||
displacementSize = 1;
|
displacementSize = 1;
|
||||||
else
|
else
|
||||||
displacementSize = 4;
|
displacementSize = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displacementSize == 1)
|
if (displacementSize == 1)
|
||||||
info.displacement = (s32)(s8)*codePtr;
|
info.displacement = (s32)(s8)*codePtr;
|
||||||
else
|
else
|
||||||
info.displacement = *((s32 *)codePtr);
|
info.displacement = *((s32 *)codePtr);
|
||||||
codePtr += displacementSize;
|
codePtr += displacementSize;
|
||||||
|
|
||||||
|
|
||||||
if (accessType == 1)
|
if (accessType == 1)
|
||||||
{
|
{
|
||||||
info.isMemoryWrite = true;
|
info.isMemoryWrite = true;
|
||||||
//Write access
|
//Write access
|
||||||
switch (codeByte)
|
switch (codeByte)
|
||||||
{
|
{
|
||||||
case 0xC6: //move 8-bit immediate
|
case 0xC6: //move 8-bit immediate
|
||||||
{
|
{
|
||||||
info.hasImmediate = true;
|
info.hasImmediate = true;
|
||||||
info.immediate = *codePtr;
|
info.immediate = *codePtr;
|
||||||
codePtr++; //move past immediate
|
codePtr++; //move past immediate
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xC7: //move 16 or 32-bit immediate, easiest case for writes
|
case 0xC7: //move 16 or 32-bit immediate, easiest case for writes
|
||||||
{
|
{
|
||||||
if (info.operandSize == 2)
|
if (info.operandSize == 2)
|
||||||
{
|
{
|
||||||
info.hasImmediate = true;
|
info.hasImmediate = true;
|
||||||
info.immediate = *(u16*)codePtr;
|
info.immediate = *(u16*)codePtr;
|
||||||
codePtr += 2;
|
codePtr += 2;
|
||||||
}
|
}
|
||||||
else if (info.operandSize == 4)
|
else if (info.operandSize == 4)
|
||||||
{
|
{
|
||||||
info.hasImmediate = true;
|
info.hasImmediate = true;
|
||||||
info.immediate = *(u32*)codePtr;
|
info.immediate = *(u32*)codePtr;
|
||||||
codePtr += 4;
|
codePtr += 4;
|
||||||
}
|
}
|
||||||
else if (info.operandSize == 8)
|
else if (info.operandSize == 8)
|
||||||
{
|
{
|
||||||
info.zeroExtend = true;
|
info.zeroExtend = true;
|
||||||
info.immediate = *(u32*)codePtr;
|
info.immediate = *(u32*)codePtr;
|
||||||
codePtr += 4;
|
codePtr += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x89: //move reg to memory
|
case 0x89: //move reg to memory
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PanicAlert("Unhandled disasm case in write handler!\n\nPlease implement or avoid.");
|
PanicAlert("Unhandled disasm case in write handler!\n\nPlease implement or avoid.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Memory read
|
// Memory read
|
||||||
|
|
||||||
//mov eax, dword ptr [rax] == 8b 00
|
//mov eax, dword ptr [rax] == 8b 00
|
||||||
switch (codeByte)
|
switch (codeByte)
|
||||||
{
|
{
|
||||||
case 0x0F:
|
case 0x0F:
|
||||||
switch (codeByte2)
|
switch (codeByte2)
|
||||||
{
|
{
|
||||||
case 0xB6: //movzx on byte
|
case 0xB6: //movzx on byte
|
||||||
info.zeroExtend = true;
|
info.zeroExtend = true;
|
||||||
info.operandSize = 1;
|
info.operandSize = 1;
|
||||||
break;
|
break;
|
||||||
case 0xB7: //movzx on short
|
case 0xB7: //movzx on short
|
||||||
info.zeroExtend = true;
|
info.zeroExtend = true;
|
||||||
info.operandSize = 2;
|
info.operandSize = 2;
|
||||||
break;
|
break;
|
||||||
case 0xBE: //movsx on byte
|
case 0xBE: //movsx on byte
|
||||||
info.signExtend = true;
|
info.signExtend = true;
|
||||||
info.operandSize = 1;
|
info.operandSize = 1;
|
||||||
break;
|
break;
|
||||||
case 0xBF:
|
case 0xBF:
|
||||||
info.signExtend = true;
|
info.signExtend = true;
|
||||||
info.operandSize = 2;
|
info.operandSize = 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x8a:
|
case 0x8a:
|
||||||
if (info.operandSize == 4)
|
if (info.operandSize == 4)
|
||||||
{
|
{
|
||||||
info.operandSize = 1;
|
info.operandSize = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
case 0x8b:
|
case 0x8b:
|
||||||
break; //it's OK don't need to do anything
|
break; //it's OK don't need to do anything
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info.instructionSize = (int)(codePtr - startCodePtr);
|
info.instructionSize = (int)(codePtr - startCodePtr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,298 +1,298 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "FileUtil.h"
|
#include "FileUtil.h"
|
||||||
|
|
||||||
#include "../HLE/HLE.h"
|
#include "../HLE/HLE.h"
|
||||||
|
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "../PowerPC/PPCAnalyst.h"
|
#include "../PowerPC/PPCAnalyst.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
#include "../HW/HW.h"
|
#include "../HW/HW.h"
|
||||||
#include "../HW/EXI_DeviceIPL.h"
|
#include "../HW/EXI_DeviceIPL.h"
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
#include "../HW/PeripheralInterface.h"
|
#include "../HW/PeripheralInterface.h"
|
||||||
#include "../HW/DVDInterface.h"
|
#include "../HW/DVDInterface.h"
|
||||||
#include "../HW/VideoInterface.h"
|
#include "../HW/VideoInterface.h"
|
||||||
#include "../HW/CPU.h"
|
#include "../HW/CPU.h"
|
||||||
|
|
||||||
#include "../Debugger/Debugger_SymbolMap.h"
|
#include "../Debugger/Debugger_SymbolMap.h"
|
||||||
#include "../Debugger/Debugger_BreakPoints.h"
|
#include "../Debugger/Debugger_BreakPoints.h"
|
||||||
|
|
||||||
#include "Boot_DOL.h"
|
#include "Boot_DOL.h"
|
||||||
#include "Boot.h"
|
#include "Boot.h"
|
||||||
#include "../Host.h"
|
#include "../Host.h"
|
||||||
#include "../VolumeHandler.h"
|
#include "../VolumeHandler.h"
|
||||||
#include "../PatchEngine.h"
|
#include "../PatchEngine.h"
|
||||||
#include "../PowerPC/SignatureDB.h"
|
#include "../PowerPC/SignatureDB.h"
|
||||||
#include "../PowerPC/SymbolDB.h"
|
#include "../PowerPC/SymbolDB.h"
|
||||||
|
|
||||||
#include "../MemTools.h"
|
#include "../MemTools.h"
|
||||||
#include "MappedFile.h"
|
#include "MappedFile.h"
|
||||||
|
|
||||||
#include "VolumeCreator.h"
|
#include "VolumeCreator.h"
|
||||||
|
|
||||||
void CBoot::Load_FST(bool _bIsWii)
|
void CBoot::Load_FST(bool _bIsWii)
|
||||||
{
|
{
|
||||||
if (VolumeHandler::IsValid())
|
if (VolumeHandler::IsValid())
|
||||||
{
|
{
|
||||||
// copy first 20 bytes of disc to start of Mem 1
|
// copy first 20 bytes of disc to start of Mem 1
|
||||||
VolumeHandler::ReadToPtr(Memory::GetPointer(0x80000000), 0, 0x20);
|
VolumeHandler::ReadToPtr(Memory::GetPointer(0x80000000), 0, 0x20);
|
||||||
|
|
||||||
// copy of game id
|
// copy of game id
|
||||||
Memory::Write_U32(Memory::Read_U32(0x80000000), 0x80003180);
|
Memory::Write_U32(Memory::Read_U32(0x80000000), 0x80003180);
|
||||||
|
|
||||||
u32 shift = 0;
|
u32 shift = 0;
|
||||||
if (_bIsWii)
|
if (_bIsWii)
|
||||||
shift = 2;
|
shift = 2;
|
||||||
|
|
||||||
u32 fstOffset = VolumeHandler::Read32(0x0424) << shift;
|
u32 fstOffset = VolumeHandler::Read32(0x0424) << shift;
|
||||||
u32 fstSize = VolumeHandler::Read32(0x0428) << shift;
|
u32 fstSize = VolumeHandler::Read32(0x0428) << shift;
|
||||||
u32 maxFstSize = VolumeHandler::Read32(0x042c) << shift;
|
u32 maxFstSize = VolumeHandler::Read32(0x042c) << shift;
|
||||||
|
|
||||||
u32 arenaHigh = 0x817FFFF4 - maxFstSize;
|
u32 arenaHigh = 0x817FFFF4 - maxFstSize;
|
||||||
Memory::Write_U32(arenaHigh, 0x00000034);
|
Memory::Write_U32(arenaHigh, 0x00000034);
|
||||||
|
|
||||||
// load FST
|
// load FST
|
||||||
VolumeHandler::ReadToPtr(Memory::GetPointer(arenaHigh), fstOffset, fstSize);
|
VolumeHandler::ReadToPtr(Memory::GetPointer(arenaHigh), fstOffset, fstSize);
|
||||||
Memory::Write_U32(arenaHigh, 0x00000038);
|
Memory::Write_U32(arenaHigh, 0x00000038);
|
||||||
Memory::Write_U32(maxFstSize, 0x0000003c);
|
Memory::Write_U32(maxFstSize, 0x0000003c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBoot::UpdateDebugger_MapLoaded(const char *_gameID)
|
void CBoot::UpdateDebugger_MapLoaded(const char *_gameID)
|
||||||
{
|
{
|
||||||
Host_NotifyMapLoaded();
|
Host_NotifyMapLoaded();
|
||||||
Host_UpdateMemoryView();
|
Host_UpdateMemoryView();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CBoot::GenerateMapFilename()
|
std::string CBoot::GenerateMapFilename()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
std::string strDriveDirectory, strFilename;
|
std::string strDriveDirectory, strFilename;
|
||||||
SplitPath(booted_file, &strDriveDirectory, &strFilename, NULL);
|
SplitPath(booted_file, &strDriveDirectory, &strFilename, NULL);
|
||||||
|
|
||||||
std::string strFullfilename(strFilename + _T(".map"));
|
std::string strFullfilename(strFilename + _T(".map"));
|
||||||
std::string strMapFilename;
|
std::string strMapFilename;
|
||||||
BuildCompleteFilename(strMapFilename, strDriveDirectory, strFullfilename);
|
BuildCompleteFilename(strMapFilename, strDriveDirectory, strFullfilename);
|
||||||
*/
|
*/
|
||||||
return FULL_MAPS_DIR + Core::GetStartupParameter().GetUniqueID() + ".map";
|
return FULL_MAPS_DIR + Core::GetStartupParameter().GetUniqueID() + ".map";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBoot::LoadMapFromFilename(const std::string &_rFilename, const char *_gameID)
|
bool CBoot::LoadMapFromFilename(const std::string &_rFilename, const char *_gameID)
|
||||||
{
|
{
|
||||||
if (_rFilename.size() == 0)
|
if (_rFilename.size() == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::string strMapFilename = GenerateMapFilename();
|
std::string strMapFilename = GenerateMapFilename();
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
if (!g_symbolDB.LoadMap(strMapFilename.c_str()))
|
if (!g_symbolDB.LoadMap(strMapFilename.c_str()))
|
||||||
{
|
{
|
||||||
if (_gameID != NULL)
|
if (_gameID != NULL)
|
||||||
{
|
{
|
||||||
BuildCompleteFilename(strMapFilename, "maps", std::string(_gameID) + ".map");
|
BuildCompleteFilename(strMapFilename, "maps", std::string(_gameID) + ".map");
|
||||||
success = g_symbolDB.LoadMap(strMapFilename.c_str());
|
success = g_symbolDB.LoadMap(strMapFilename.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
UpdateDebugger_MapLoaded();
|
UpdateDebugger_MapLoaded();
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBoot::Load_BIOS(const std::string& _rBiosFilename)
|
bool CBoot::Load_BIOS(const std::string& _rBiosFilename)
|
||||||
{
|
{
|
||||||
bool bResult = false;
|
bool bResult = false;
|
||||||
Common::IMappedFile* pFile = Common::IMappedFile::CreateMappedFileDEPRECATED();
|
Common::IMappedFile* pFile = Common::IMappedFile::CreateMappedFileDEPRECATED();
|
||||||
if (pFile->Open(_rBiosFilename.c_str()))
|
if (pFile->Open(_rBiosFilename.c_str()))
|
||||||
{
|
{
|
||||||
if (pFile->GetSize() >= 1024*1024*2)
|
if (pFile->GetSize() >= 1024*1024*2)
|
||||||
{
|
{
|
||||||
u32 CopySize = (u32)pFile->GetSize() - 0x820;
|
u32 CopySize = (u32)pFile->GetSize() - 0x820;
|
||||||
u8* pData = pFile->Lock(0x820, CopySize);
|
u8* pData = pFile->Lock(0x820, CopySize);
|
||||||
Memory::WriteBigEData(pData, 0x81300000, CopySize);
|
Memory::WriteBigEData(pData, 0x81300000, CopySize);
|
||||||
pFile->Unlock(pData);
|
pFile->Unlock(pData);
|
||||||
pFile->Close();
|
pFile->Close();
|
||||||
|
|
||||||
PC = 0x81300000;
|
PC = 0x81300000;
|
||||||
|
|
||||||
bResult = true;
|
bResult = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete pFile;
|
delete pFile;
|
||||||
return bResult;
|
return bResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBoot::BootUp(const SCoreStartupParameter& _StartupPara)
|
bool CBoot::BootUp(const SCoreStartupParameter& _StartupPara)
|
||||||
{
|
{
|
||||||
const bool bDebugIsoBootup = false;
|
const bool bDebugIsoBootup = false;
|
||||||
|
|
||||||
g_symbolDB.Clear();
|
g_symbolDB.Clear();
|
||||||
VideoInterface::PreInit(_StartupPara.bNTSC);
|
VideoInterface::PreInit(_StartupPara.bNTSC);
|
||||||
switch (_StartupPara.m_BootType)
|
switch (_StartupPara.m_BootType)
|
||||||
{
|
{
|
||||||
// GCM
|
// GCM
|
||||||
// ===================================================================================
|
// ===================================================================================
|
||||||
case SCoreStartupParameter::BOOT_ISO:
|
case SCoreStartupParameter::BOOT_ISO:
|
||||||
{
|
{
|
||||||
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(_StartupPara.m_strFilename);
|
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(_StartupPara.m_strFilename);
|
||||||
if (pVolume == NULL)
|
if (pVolume == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
bool isoWii = DiscIO::IsVolumeWiiDisc(pVolume);
|
bool isoWii = DiscIO::IsVolumeWiiDisc(pVolume);
|
||||||
if (isoWii != Core::GetStartupParameter().bWii)
|
if (isoWii != Core::GetStartupParameter().bWii)
|
||||||
{
|
{
|
||||||
PanicAlert("Warning - starting ISO in wrong console mode!");
|
PanicAlert("Warning - starting ISO in wrong console mode!");
|
||||||
}
|
}
|
||||||
|
|
||||||
char gameID[7];
|
char gameID[7];
|
||||||
memcpy(gameID, pVolume->GetUniqueID().c_str(), 6);
|
memcpy(gameID, pVolume->GetUniqueID().c_str(), 6);
|
||||||
gameID[6] = 0;
|
gameID[6] = 0;
|
||||||
|
|
||||||
// setup the map from ISOFile ID
|
// setup the map from ISOFile ID
|
||||||
VolumeHandler::SetVolumeName(_StartupPara.m_strFilename);
|
VolumeHandler::SetVolumeName(_StartupPara.m_strFilename);
|
||||||
|
|
||||||
DVDInterface::SetDiscInside(true);
|
DVDInterface::SetDiscInside(true);
|
||||||
|
|
||||||
if (_StartupPara.bHLEBios)
|
if (_StartupPara.bHLEBios)
|
||||||
{
|
{
|
||||||
if (!VolumeHandler::IsWii())
|
if (!VolumeHandler::IsWii())
|
||||||
EmulatedBIOS(bDebugIsoBootup);
|
EmulatedBIOS(bDebugIsoBootup);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Core::g_CoreStartupParameter.bWii = true;
|
Core::g_CoreStartupParameter.bWii = true;
|
||||||
EmulatedBIOS_Wii(bDebugIsoBootup);
|
EmulatedBIOS_Wii(bDebugIsoBootup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!Load_BIOS(_StartupPara.m_strBios))
|
if (!Load_BIOS(_StartupPara.m_strBios))
|
||||||
{
|
{
|
||||||
// fails to load a BIOS so HLE it
|
// fails to load a BIOS so HLE it
|
||||||
if (!VolumeHandler::IsWii())
|
if (!VolumeHandler::IsWii())
|
||||||
EmulatedBIOS(bDebugIsoBootup);
|
EmulatedBIOS(bDebugIsoBootup);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Core::g_CoreStartupParameter.bWii = true;
|
Core::g_CoreStartupParameter.bWii = true;
|
||||||
EmulatedBIOS_Wii(bDebugIsoBootup);
|
EmulatedBIOS_Wii(bDebugIsoBootup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (LoadMapFromFilename(_StartupPara.m_strFilename, gameID))
|
if (LoadMapFromFilename(_StartupPara.m_strFilename, gameID))
|
||||||
HLE::PatchFunctions();
|
HLE::PatchFunctions();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DOL
|
// DOL
|
||||||
// ===================================================================================
|
// ===================================================================================
|
||||||
case SCoreStartupParameter::BOOT_DOL:
|
case SCoreStartupParameter::BOOT_DOL:
|
||||||
{
|
{
|
||||||
CDolLoader dolLoader(_StartupPara.m_strFilename.c_str());
|
CDolLoader dolLoader(_StartupPara.m_strFilename.c_str());
|
||||||
PC = dolLoader.GetEntryPoint();
|
PC = dolLoader.GetEntryPoint();
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if (LoadMapFromFilename(_StartupPara.m_strFilename))
|
if (LoadMapFromFilename(_StartupPara.m_strFilename))
|
||||||
HLE::PatchFunctions();
|
HLE::PatchFunctions();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// ELF
|
// ELF
|
||||||
// ===================================================================================
|
// ===================================================================================
|
||||||
case SCoreStartupParameter::BOOT_ELF:
|
case SCoreStartupParameter::BOOT_ELF:
|
||||||
{
|
{
|
||||||
if(!File::Exists(_StartupPara.m_strFilename.c_str()))
|
if(!File::Exists(_StartupPara.m_strFilename.c_str()))
|
||||||
{
|
{
|
||||||
PanicAlert("The file you specified (%s) does not exists",
|
PanicAlert("The file you specified (%s) does not exists",
|
||||||
_StartupPara.m_strFilename.c_str());
|
_StartupPara.m_strFilename.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have gotten a Wii file or not
|
// Check if we have gotten a Wii file or not
|
||||||
bool elfWii = IsElfWii(_StartupPara.m_strFilename.c_str());
|
bool elfWii = IsElfWii(_StartupPara.m_strFilename.c_str());
|
||||||
if (elfWii != Core::GetStartupParameter().bWii)
|
if (elfWii != Core::GetStartupParameter().bWii)
|
||||||
{
|
{
|
||||||
PanicAlert("Warning - starting ELF in wrong console mode!");
|
PanicAlert("Warning - starting ELF in wrong console mode!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop apploader from running when BIOS boots
|
// stop apploader from running when BIOS boots
|
||||||
VolumeHandler::SetVolumeName("");
|
VolumeHandler::SetVolumeName("");
|
||||||
|
|
||||||
if (elfWii)
|
if (elfWii)
|
||||||
{
|
{
|
||||||
EmulatedBIOS_Wii(false);
|
EmulatedBIOS_Wii(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!VolumeHandler::IsWii() && !_StartupPara.m_strDefaultGCM.empty())
|
if (!VolumeHandler::IsWii() && !_StartupPara.m_strDefaultGCM.empty())
|
||||||
{
|
{
|
||||||
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM.c_str());
|
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM.c_str());
|
||||||
EmulatedBIOS(false);
|
EmulatedBIOS(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load image or create virtual drive from directory
|
// load image or create virtual drive from directory
|
||||||
if (!_StartupPara.m_strDVDRoot.empty())
|
if (!_StartupPara.m_strDVDRoot.empty())
|
||||||
VolumeHandler::SetVolumeDirectory(_StartupPara.m_strDVDRoot, elfWii);
|
VolumeHandler::SetVolumeDirectory(_StartupPara.m_strDVDRoot, elfWii);
|
||||||
else if (!_StartupPara.m_strDefaultGCM.empty())
|
else if (!_StartupPara.m_strDefaultGCM.empty())
|
||||||
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM);
|
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM);
|
||||||
else
|
else
|
||||||
VolumeHandler::SetVolumeDirectory(_StartupPara.m_strFilename, elfWii);
|
VolumeHandler::SetVolumeDirectory(_StartupPara.m_strFilename, elfWii);
|
||||||
|
|
||||||
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
|
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
|
||||||
|
|
||||||
Load_FST(elfWii);
|
Load_FST(elfWii);
|
||||||
|
|
||||||
Boot_ELF(_StartupPara.m_strFilename.c_str());
|
Boot_ELF(_StartupPara.m_strFilename.c_str());
|
||||||
UpdateDebugger_MapLoaded();
|
UpdateDebugger_MapLoaded();
|
||||||
CBreakPoints::AddAutoBreakpoints();
|
CBreakPoints::AddAutoBreakpoints();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// BIOS
|
// BIOS
|
||||||
// ===================================================================================
|
// ===================================================================================
|
||||||
case SCoreStartupParameter::BOOT_BIOS:
|
case SCoreStartupParameter::BOOT_BIOS:
|
||||||
{
|
{
|
||||||
DVDInterface::SetDiscInside(false);
|
DVDInterface::SetDiscInside(false);
|
||||||
if (Load_BIOS(_StartupPara.m_strBios))
|
if (Load_BIOS(_StartupPara.m_strBios))
|
||||||
{
|
{
|
||||||
if (LoadMapFromFilename(_StartupPara.m_strFilename))
|
if (LoadMapFromFilename(_StartupPara.m_strFilename))
|
||||||
HLE::PatchFunctions();
|
HLE::PatchFunctions();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
PanicAlert("Tried to load an unknown file type.");
|
PanicAlert("Tried to load an unknown file type.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Host_UpdateLogDisplay();
|
Host_UpdateLogDisplay();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,400 +1,400 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
#include "../HW/EXI_DeviceIPL.h"
|
#include "../HW/EXI_DeviceIPL.h"
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
#include "../HW/DVDInterface.h"
|
#include "../HW/DVDInterface.h"
|
||||||
#include "../HW/CPU.h"
|
#include "../HW/CPU.h"
|
||||||
|
|
||||||
#include "../Host.h"
|
#include "../Host.h"
|
||||||
#include "../VolumeHandler.h"
|
#include "../VolumeHandler.h"
|
||||||
#include "../PatchEngine.h"
|
#include "../PatchEngine.h"
|
||||||
#include "../MemTools.h"
|
#include "../MemTools.h"
|
||||||
|
|
||||||
#include "VolumeCreator.h"
|
#include "VolumeCreator.h"
|
||||||
#include "Boot.h"
|
#include "Boot.h"
|
||||||
|
|
||||||
void CBoot::RunFunction(u32 _iAddr, bool _bUseDebugger)
|
void CBoot::RunFunction(u32 _iAddr, bool _bUseDebugger)
|
||||||
{
|
{
|
||||||
PC = _iAddr;
|
PC = _iAddr;
|
||||||
LR = 0x00;
|
LR = 0x00;
|
||||||
|
|
||||||
if (_bUseDebugger)
|
if (_bUseDebugger)
|
||||||
{
|
{
|
||||||
CCPU::Break();
|
CCPU::Break();
|
||||||
while (PC != 0x00)
|
while (PC != 0x00)
|
||||||
CCPU::SingleStep();
|
CCPU::SingleStep();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (PC != 0x00)
|
while (PC != 0x00)
|
||||||
PowerPC::SingleStep();
|
PowerPC::SingleStep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
//
|
//
|
||||||
// BIOS HLE:
|
// BIOS HLE:
|
||||||
// copy the apploader to 0x81200000
|
// copy the apploader to 0x81200000
|
||||||
// execute the apploader
|
// execute the apploader
|
||||||
//
|
//
|
||||||
void CBoot::EmulatedBIOS(bool _bDebug)
|
void CBoot::EmulatedBIOS(bool _bDebug)
|
||||||
{
|
{
|
||||||
LOG(BOOT, "Faking GC BIOS...");
|
LOG(BOOT, "Faking GC BIOS...");
|
||||||
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
|
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
|
||||||
m_MSR.FP = 1;
|
m_MSR.FP = 1;
|
||||||
|
|
||||||
Memory::Clear();
|
Memory::Clear();
|
||||||
|
|
||||||
// =======================================================================================
|
// =======================================================================================
|
||||||
// Write necessary values
|
// Write necessary values
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
/* Here we write values to memory that the apploader does not take care of. Game iso info goes
|
/* Here we write values to memory that the apploader does not take care of. Game iso info goes
|
||||||
to 0x80000000 according to yagcd 4.2. I'm not sure what bytes 8-10 does (version and
|
to 0x80000000 according to yagcd 4.2. I'm not sure what bytes 8-10 does (version and
|
||||||
streaming), but I include them anyway because it seems like they are supposed to be there. */
|
streaming), but I include them anyway because it seems like they are supposed to be there. */
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
DVDInterface::DVDRead(0x00000000, 0x80000000, 10); // write boot info needed for multidisc games
|
DVDInterface::DVDRead(0x00000000, 0x80000000, 10); // write boot info needed for multidisc games
|
||||||
|
|
||||||
Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
|
Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
|
||||||
Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
|
Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
|
||||||
Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
|
Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
|
||||||
//
|
//
|
||||||
Memory::Write_U32(0xc2339f3d, 0x8000001C); //game disc
|
Memory::Write_U32(0xc2339f3d, 0x8000001C); //game disc
|
||||||
Memory::Write_U32(0x0D15EA5E, 0x80000020); //funny magic word for normal boot
|
Memory::Write_U32(0x0D15EA5E, 0x80000020); //funny magic word for normal boot
|
||||||
Memory::Write_U32(0x01800000, 0x80000028); // Physical Memory Size
|
Memory::Write_U32(0x01800000, 0x80000028); // Physical Memory Size
|
||||||
|
|
||||||
// Memory::Write_U32(0x00000003, 0x8000002C); // Console type - retail
|
// Memory::Write_U32(0x00000003, 0x8000002C); // Console type - retail
|
||||||
Memory::Write_U32(0x10000006, 0x8000002C); // DevKit
|
Memory::Write_U32(0x10000006, 0x8000002C); // DevKit
|
||||||
|
|
||||||
Memory::Write_U32(((1 & 0x3f) << 26) | 2, 0x81300000); // HLE OSReport for Apploader
|
Memory::Write_U32(((1 & 0x3f) << 26) | 2, 0x81300000); // HLE OSReport for Apploader
|
||||||
// =======================================================================================
|
// =======================================================================================
|
||||||
|
|
||||||
|
|
||||||
// =======================================================================================
|
// =======================================================================================
|
||||||
// Load Apploader to Memory - The apploader is hardcoded to begin at byte 9 280 on the disc,
|
// Load Apploader to Memory - The apploader is hardcoded to begin at byte 9 280 on the disc,
|
||||||
// but it seems like the size can be variable. Compare with yagcd chap 13.
|
// but it seems like the size can be variable. Compare with yagcd chap 13.
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
|
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
|
||||||
u32 iAppLoaderOffset = 0x2440; // 0x1c40 (what is 0x1c40?)
|
u32 iAppLoaderOffset = 0x2440; // 0x1c40 (what is 0x1c40?)
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
|
u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
|
||||||
u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14);
|
u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14);
|
||||||
if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
|
if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
|
||||||
return;
|
return;
|
||||||
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
|
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
|
||||||
// =======================================================================================
|
// =======================================================================================
|
||||||
|
|
||||||
|
|
||||||
//call iAppLoaderEntry
|
//call iAppLoaderEntry
|
||||||
LOG(MASTER_LOG, "Call iAppLoaderEntry");
|
LOG(MASTER_LOG, "Call iAppLoaderEntry");
|
||||||
|
|
||||||
u32 iAppLoaderFuncAddr = 0x80003100;
|
u32 iAppLoaderFuncAddr = 0x80003100;
|
||||||
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
|
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
|
||||||
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
|
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
|
||||||
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
|
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
|
||||||
RunFunction(iAppLoaderEntry, _bDebug);
|
RunFunction(iAppLoaderEntry, _bDebug);
|
||||||
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
|
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
|
||||||
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
|
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
|
||||||
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
|
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
|
||||||
|
|
||||||
// iAppLoaderInit
|
// iAppLoaderInit
|
||||||
LOG(MASTER_LOG, "Call iAppLoaderInit");
|
LOG(MASTER_LOG, "Call iAppLoaderInit");
|
||||||
PowerPC::ppcState.gpr[3] = 0x81300000;
|
PowerPC::ppcState.gpr[3] = 0x81300000;
|
||||||
RunFunction(iAppLoaderInit, _bDebug);
|
RunFunction(iAppLoaderInit, _bDebug);
|
||||||
|
|
||||||
|
|
||||||
// =======================================================================================
|
// =======================================================================================
|
||||||
/* iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem).
|
/* iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem).
|
||||||
To give you an idea about where the stuff is located on the disc take a look at yagcd
|
To give you an idea about where the stuff is located on the disc take a look at yagcd
|
||||||
ch 13. */
|
ch 13. */
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
LOG(MASTER_LOG, "Call iAppLoaderMain");
|
LOG(MASTER_LOG, "Call iAppLoaderMain");
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.gpr[3] = 0x81300004;
|
PowerPC::ppcState.gpr[3] = 0x81300004;
|
||||||
PowerPC::ppcState.gpr[4] = 0x81300008;
|
PowerPC::ppcState.gpr[4] = 0x81300008;
|
||||||
PowerPC::ppcState.gpr[5] = 0x8130000c;
|
PowerPC::ppcState.gpr[5] = 0x8130000c;
|
||||||
|
|
||||||
RunFunction(iAppLoaderMain, _bDebug);
|
RunFunction(iAppLoaderMain, _bDebug);
|
||||||
|
|
||||||
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
|
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
|
||||||
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
|
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
|
||||||
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c);
|
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c);
|
||||||
|
|
||||||
LOGV(MASTER_LOG, 2, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
LOGV(MASTER_LOG, 2, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
||||||
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
|
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
|
||||||
|
|
||||||
} while(PowerPC::ppcState.gpr[3] != 0x00);
|
} while(PowerPC::ppcState.gpr[3] != 0x00);
|
||||||
// =======================================================================================
|
// =======================================================================================
|
||||||
|
|
||||||
|
|
||||||
// iAppLoaderClose
|
// iAppLoaderClose
|
||||||
LOG(MASTER_LOG, "call iAppLoaderClose");
|
LOG(MASTER_LOG, "call iAppLoaderClose");
|
||||||
RunFunction(iAppLoaderClose, _bDebug);
|
RunFunction(iAppLoaderClose, _bDebug);
|
||||||
|
|
||||||
// Load patches
|
// Load patches
|
||||||
std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
|
std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
|
||||||
PatchEngine::LoadPatches(gameID.c_str());
|
PatchEngine::LoadPatches(gameID.c_str());
|
||||||
PowerPC::ppcState.DebugCount = 0;
|
PowerPC::ppcState.DebugCount = 0;
|
||||||
// return
|
// return
|
||||||
PC = PowerPC::ppcState.gpr[3];
|
PC = PowerPC::ppcState.gpr[3];
|
||||||
|
|
||||||
// --- preinit some stuff from bios ---
|
// --- preinit some stuff from bios ---
|
||||||
|
|
||||||
// Bus Clock Speed
|
// Bus Clock Speed
|
||||||
Memory::Write_U32(0x09a7ec80, 0x800000F8);
|
Memory::Write_U32(0x09a7ec80, 0x800000F8);
|
||||||
Memory::Write_U32(0x1cf7c580, 0x800000FC);
|
Memory::Write_U32(0x1cf7c580, 0x800000FC);
|
||||||
|
|
||||||
// fake the VI Init of the BIOS
|
// fake the VI Init of the BIOS
|
||||||
Memory::Write_U32(Core::g_CoreStartupParameter.bNTSC ? 0 : 1, 0x800000CC);
|
Memory::Write_U32(Core::g_CoreStartupParameter.bNTSC ? 0 : 1, 0x800000CC);
|
||||||
|
|
||||||
// preset time
|
// preset time
|
||||||
Memory::Write_U32(CEXIIPL::GetGCTime(), 0x800030D8);
|
Memory::Write_U32(CEXIIPL::GetGCTime(), 0x800030D8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
//
|
//
|
||||||
// BIOS HLE:
|
// BIOS HLE:
|
||||||
// copy the apploader to 0x81200000
|
// copy the apploader to 0x81200000
|
||||||
// execute the apploader
|
// execute the apploader
|
||||||
//
|
//
|
||||||
bool CBoot::EmulatedBIOS_Wii(bool _bDebug)
|
bool CBoot::EmulatedBIOS_Wii(bool _bDebug)
|
||||||
{
|
{
|
||||||
LOG(BOOT, "Faking Wii BIOS...");
|
LOG(BOOT, "Faking Wii BIOS...");
|
||||||
|
|
||||||
FILE* pDump = fopen(FULL_WII_SYS_DIR "dump_0x0000_0x4000.bin", "rb");
|
FILE* pDump = fopen(FULL_WII_SYS_DIR "dump_0x0000_0x4000.bin", "rb");
|
||||||
if (pDump != NULL)
|
if (pDump != NULL)
|
||||||
{
|
{
|
||||||
LOG(MASTER_LOG, "Init from memory dump.");
|
LOG(MASTER_LOG, "Init from memory dump.");
|
||||||
|
|
||||||
fread(Memory::GetMainRAMPtr(), 1, 16384, pDump);
|
fread(Memory::GetMainRAMPtr(), 1, 16384, pDump);
|
||||||
fclose(pDump);
|
fclose(pDump);
|
||||||
pDump = NULL;
|
pDump = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// =======================================================
|
// =======================================================
|
||||||
/* Write the 256 byte setting.txt to memory. This may not be needed as
|
/* Write the 256 byte setting.txt to memory. This may not be needed as
|
||||||
most or all games read the setting.txt file from \title\00000001\00000002\
|
most or all games read the setting.txt file from \title\00000001\00000002\
|
||||||
data\setting.txt directly after the read the SYSCONF file. The games also
|
data\setting.txt directly after the read the SYSCONF file. The games also
|
||||||
read it to 0x3800, what is a little strange however is that it only reads
|
read it to 0x3800, what is a little strange however is that it only reads
|
||||||
the first 100 bytes of it. */
|
the first 100 bytes of it. */
|
||||||
// -------------
|
// -------------
|
||||||
{
|
{
|
||||||
std::string filename(WII_EUR_SETTING_FILE);
|
std::string filename(WII_EUR_SETTING_FILE);
|
||||||
if (VolumeHandler::IsValid())
|
if (VolumeHandler::IsValid())
|
||||||
{
|
{
|
||||||
switch(VolumeHandler::GetVolume()->GetCountry())
|
switch(VolumeHandler::GetVolume()->GetCountry())
|
||||||
{
|
{
|
||||||
case DiscIO::IVolume::COUNTRY_JAP:
|
case DiscIO::IVolume::COUNTRY_JAP:
|
||||||
filename = WII_JAP_SETTING_FILE;
|
filename = WII_JAP_SETTING_FILE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DiscIO::IVolume::COUNTRY_USA:
|
case DiscIO::IVolume::COUNTRY_USA:
|
||||||
filename = WII_USA_SETTING_FILE;
|
filename = WII_USA_SETTING_FILE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DiscIO::IVolume::COUNTRY_EUROPE:
|
case DiscIO::IVolume::COUNTRY_EUROPE:
|
||||||
filename = WII_EUR_SETTING_FILE;
|
filename = WII_EUR_SETTING_FILE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PanicAlert("Unknown country. Wii boot process will be switched to European settings.");
|
PanicAlert("Unknown country. Wii boot process will be switched to European settings.");
|
||||||
filename = WII_EUR_SETTING_FILE;
|
filename = WII_EUR_SETTING_FILE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* pTmp = fopen(filename.c_str(), "rb");
|
FILE* pTmp = fopen(filename.c_str(), "rb");
|
||||||
if (!pTmp)
|
if (!pTmp)
|
||||||
{
|
{
|
||||||
LOG(MASTER_LOG, "Cant find setting file");
|
LOG(MASTER_LOG, "Cant find setting file");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fread(Memory::GetPointer(0x3800), 256, 1, pTmp);
|
fread(Memory::GetPointer(0x3800), 256, 1, pTmp);
|
||||||
fclose(pTmp);
|
fclose(pTmp);
|
||||||
}
|
}
|
||||||
// =============
|
// =============
|
||||||
|
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
/* Set hardcoded global variables to Wii memory. These are partly collected from
|
/* Set hardcoded global variables to Wii memory. These are partly collected from
|
||||||
Wiibrew. These values are needed for the games to function correctly. A few
|
Wiibrew. These values are needed for the games to function correctly. A few
|
||||||
values in this region will also be placed here by the game as it boots.
|
values in this region will also be placed here by the game as it boots.
|
||||||
They are:
|
They are:
|
||||||
|
|
||||||
// Strange values that I don't know the meaning of, all games write these
|
// Strange values that I don't know the meaning of, all games write these
|
||||||
0x00 to 0x18: 0x029f0010
|
0x00 to 0x18: 0x029f0010
|
||||||
0x029f0033
|
0x029f0033
|
||||||
0x029f0034
|
0x029f0034
|
||||||
0x029f0035
|
0x029f0035
|
||||||
0x029f0036
|
0x029f0036
|
||||||
0x029f0037
|
0x029f0037
|
||||||
0x029f0038
|
0x029f0038
|
||||||
0x029f0039 // Replaces the previous 0x5d1c9ea3 magic word
|
0x029f0039 // Replaces the previous 0x5d1c9ea3 magic word
|
||||||
|
|
||||||
0x80000038 Start of FST
|
0x80000038 Start of FST
|
||||||
0x8000003c Size of FST Size
|
0x8000003c Size of FST Size
|
||||||
0x80000060 Copyright code */
|
0x80000060 Copyright code */
|
||||||
// -------------
|
// -------------
|
||||||
{
|
{
|
||||||
DVDInterface::DVDRead(0x00000000, 0x00000000, 6); // Game Code
|
DVDInterface::DVDRead(0x00000000, 0x00000000, 6); // Game Code
|
||||||
Memory::Write_U32(0x5d1c9ea3, 0x00000018); // Magic word it is a wii disc
|
Memory::Write_U32(0x5d1c9ea3, 0x00000018); // Magic word it is a wii disc
|
||||||
Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
|
Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
|
||||||
Memory::Write_U32(0x00000001, 0x00000024); // Unknown
|
Memory::Write_U32(0x00000001, 0x00000024); // Unknown
|
||||||
Memory::Write_U32(0x01800000, 0x00000028); // MEM1 size 24MB
|
Memory::Write_U32(0x01800000, 0x00000028); // MEM1 size 24MB
|
||||||
Memory::Write_U32(0x00000023, 0x0000002c); // Production Board Model
|
Memory::Write_U32(0x00000023, 0x0000002c); // Production Board Model
|
||||||
Memory::Write_U32(0x00000000, 0x00000030); // Init
|
Memory::Write_U32(0x00000000, 0x00000030); // Init
|
||||||
Memory::Write_U32(0x817FEC60, 0x00000034); // Init
|
Memory::Write_U32(0x817FEC60, 0x00000034); // Init
|
||||||
// 38, 3C should get start, size of FST through apploader
|
// 38, 3C should get start, size of FST through apploader
|
||||||
Memory::Write_U32(0x38a00040, 0x00000060); // Exception init
|
Memory::Write_U32(0x38a00040, 0x00000060); // Exception init
|
||||||
Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init
|
Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init
|
||||||
Memory::Write_U32(0x01800000, 0x000000f0); // "Simulated memory size" (debug mode?)
|
Memory::Write_U32(0x01800000, 0x000000f0); // "Simulated memory size" (debug mode?)
|
||||||
Memory::Write_U32(0x8179b500, 0x000000f4); // __start
|
Memory::Write_U32(0x8179b500, 0x000000f4); // __start
|
||||||
Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed
|
Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed
|
||||||
Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed
|
Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed
|
||||||
Memory::Write_U16(0x0000, 0x000030e6); // Console type
|
Memory::Write_U16(0x0000, 0x000030e6); // Console type
|
||||||
Memory::Write_U32(0x00000000, 0x000030c0); // EXI
|
Memory::Write_U32(0x00000000, 0x000030c0); // EXI
|
||||||
Memory::Write_U32(0x00000000, 0x000030c4); // EXI
|
Memory::Write_U32(0x00000000, 0x000030c4); // EXI
|
||||||
Memory::Write_U32(0x00000000, 0x000030dc); // Time
|
Memory::Write_U32(0x00000000, 0x000030dc); // Time
|
||||||
Memory::Write_U32(0x00000000, 0x000030d8); // Time
|
Memory::Write_U32(0x00000000, 0x000030d8); // Time
|
||||||
Memory::Write_U32(0x00000000, 0x000030f0); // Apploader
|
Memory::Write_U32(0x00000000, 0x000030f0); // Apploader
|
||||||
Memory::Write_U32(0x01800000, 0x00003100); // BAT
|
Memory::Write_U32(0x01800000, 0x00003100); // BAT
|
||||||
Memory::Write_U32(0x01800000, 0x00003104); // BAT
|
Memory::Write_U32(0x01800000, 0x00003104); // BAT
|
||||||
Memory::Write_U32(0x00000000, 0x0000310c); // Init
|
Memory::Write_U32(0x00000000, 0x0000310c); // Init
|
||||||
Memory::Write_U32(0x8179d500, 0x00003110); // Init
|
Memory::Write_U32(0x8179d500, 0x00003110); // Init
|
||||||
Memory::Write_U32(0x04000000, 0x00003118); // Unknown
|
Memory::Write_U32(0x04000000, 0x00003118); // Unknown
|
||||||
Memory::Write_U32(0x04000000, 0x0000311c); // BAT
|
Memory::Write_U32(0x04000000, 0x0000311c); // BAT
|
||||||
Memory::Write_U32(0x93400000, 0x00003120); // BAT
|
Memory::Write_U32(0x93400000, 0x00003120); // BAT
|
||||||
Memory::Write_U32(0x90000800, 0x00003124); // Init - MEM2 low
|
Memory::Write_U32(0x90000800, 0x00003124); // Init - MEM2 low
|
||||||
Memory::Write_U32(0x933e0000, 0x00003128); // Init - MEM2 high
|
Memory::Write_U32(0x933e0000, 0x00003128); // Init - MEM2 high
|
||||||
Memory::Write_U32(0x933e0000, 0x00003130); // IOS MEM2 low
|
Memory::Write_U32(0x933e0000, 0x00003130); // IOS MEM2 low
|
||||||
Memory::Write_U32(0x93400000, 0x00003134); // IOS MEM2 high
|
Memory::Write_U32(0x93400000, 0x00003134); // IOS MEM2 high
|
||||||
Memory::Write_U32(0x00000011, 0x00003138); // Console type
|
Memory::Write_U32(0x00000011, 0x00003138); // Console type
|
||||||
Memory::Write_U64(0x0009020400062507ULL, 0x00003140); // IOS Version
|
Memory::Write_U64(0x0009020400062507ULL, 0x00003140); // IOS Version
|
||||||
Memory::Write_U16(0x0113, 0x0000315e); // Apploader
|
Memory::Write_U16(0x0113, 0x0000315e); // Apploader
|
||||||
Memory::Write_U32(0x0000FF16, 0x00003158); // DDR ram vendor code
|
Memory::Write_U32(0x0000FF16, 0x00003158); // DDR ram vendor code
|
||||||
|
|
||||||
Memory::Write_U8(0x80, 0x0000315c); // OSInit
|
Memory::Write_U8(0x80, 0x0000315c); // OSInit
|
||||||
Memory::Write_U8(0x00, 0x00000006); // DVDInit
|
Memory::Write_U8(0x00, 0x00000006); // DVDInit
|
||||||
Memory::Write_U8(0x00, 0x00000007); // DVDInit
|
Memory::Write_U8(0x00, 0x00000007); // DVDInit
|
||||||
Memory::Write_U16(0x0000, 0x000030e0); // PADInit
|
Memory::Write_U16(0x0000, 0x000030e0); // PADInit
|
||||||
|
|
||||||
// Fake the VI Init of the BIOS
|
// Fake the VI Init of the BIOS
|
||||||
Memory::Write_U32(Core::g_CoreStartupParameter.bNTSC ? 0 : 1, 0x000000CC);
|
Memory::Write_U32(Core::g_CoreStartupParameter.bNTSC ? 0 : 1, 0x000000CC);
|
||||||
|
|
||||||
// Clear exception handler. Why? Don't we begin with only zeroes?
|
// Clear exception handler. Why? Don't we begin with only zeroes?
|
||||||
for (int i = 0x3000; i <= 0x3038; i += 4)
|
for (int i = 0x3000; i <= 0x3038; i += 4)
|
||||||
{
|
{
|
||||||
Memory::Write_U32(0x00000000, 0x80000000 + i);
|
Memory::Write_U32(0x00000000, 0x80000000 + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is some kind of consistency check that is compared to the 0x00
|
/* This is some kind of consistency check that is compared to the 0x00
|
||||||
values as the game boots. This location keep the 4 byte ID for as long
|
values as the game boots. This location keep the 4 byte ID for as long
|
||||||
as the game is running. The 6 byte ID at 0x00 is overwritten sometime
|
as the game is running. The 6 byte ID at 0x00 is overwritten sometime
|
||||||
after this check during booting. */
|
after this check during booting. */
|
||||||
VolumeHandler::ReadToPtr(Memory::GetPointer(0x3180), 0, 4);
|
VolumeHandler::ReadToPtr(Memory::GetPointer(0x3180), 0, 4);
|
||||||
Memory::Write_U8(0x80, 0x00003184);
|
Memory::Write_U8(0x80, 0x00003184);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// apploader
|
// apploader
|
||||||
if (VolumeHandler::IsValid() && VolumeHandler::IsWii())
|
if (VolumeHandler::IsValid() && VolumeHandler::IsWii())
|
||||||
{
|
{
|
||||||
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
|
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
|
||||||
m_MSR.FP = 1;
|
m_MSR.FP = 1;
|
||||||
|
|
||||||
//TODO: Game iso info to 0x80000000 according to yagcd - or does apploader do this?
|
//TODO: Game iso info to 0x80000000 according to yagcd - or does apploader do this?
|
||||||
|
|
||||||
Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
|
Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
|
||||||
Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
|
Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
|
||||||
Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
|
Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
|
||||||
|
|
||||||
Memory::Write_U32(((1 & 0x3f) << 26) | 2, 0x81300000); // HLE OSReport for Apploader
|
Memory::Write_U32(((1 & 0x3f) << 26) | 2, 0x81300000); // HLE OSReport for Apploader
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
|
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
|
||||||
|
|
||||||
u32 iAppLoaderOffset = 0x2440; // 0x1c40;
|
u32 iAppLoaderOffset = 0x2440; // 0x1c40;
|
||||||
|
|
||||||
// Load Apploader to Memory
|
// Load Apploader to Memory
|
||||||
u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
|
u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
|
||||||
u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14);
|
u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14);
|
||||||
if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
|
if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
|
||||||
{
|
{
|
||||||
LOG(BOOT, "Invalid apploader. Probably your image is corrupted.");
|
LOG(BOOT, "Invalid apploader. Probably your image is corrupted.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
|
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
|
||||||
|
|
||||||
//call iAppLoaderEntry
|
//call iAppLoaderEntry
|
||||||
LOG(BOOT, "Call iAppLoaderEntry");
|
LOG(BOOT, "Call iAppLoaderEntry");
|
||||||
|
|
||||||
u32 iAppLoaderFuncAddr = 0x80004000;
|
u32 iAppLoaderFuncAddr = 0x80004000;
|
||||||
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
|
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
|
||||||
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
|
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
|
||||||
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
|
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
|
||||||
RunFunction(iAppLoaderEntry, _bDebug);
|
RunFunction(iAppLoaderEntry, _bDebug);
|
||||||
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
|
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
|
||||||
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
|
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
|
||||||
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
|
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
|
||||||
|
|
||||||
// iAppLoaderInit
|
// iAppLoaderInit
|
||||||
LOG(BOOT, "Call iAppLoaderInit");
|
LOG(BOOT, "Call iAppLoaderInit");
|
||||||
PowerPC::ppcState.gpr[3] = 0x81300000;
|
PowerPC::ppcState.gpr[3] = 0x81300000;
|
||||||
RunFunction(iAppLoaderInit, _bDebug);
|
RunFunction(iAppLoaderInit, _bDebug);
|
||||||
|
|
||||||
// iAppLoaderMain
|
// iAppLoaderMain
|
||||||
LOG(BOOT, "Call iAppLoaderMain");
|
LOG(BOOT, "Call iAppLoaderMain");
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.gpr[3] = 0x81300004;
|
PowerPC::ppcState.gpr[3] = 0x81300004;
|
||||||
PowerPC::ppcState.gpr[4] = 0x81300008;
|
PowerPC::ppcState.gpr[4] = 0x81300008;
|
||||||
PowerPC::ppcState.gpr[5] = 0x8130000c;
|
PowerPC::ppcState.gpr[5] = 0x8130000c;
|
||||||
|
|
||||||
RunFunction(iAppLoaderMain, _bDebug);
|
RunFunction(iAppLoaderMain, _bDebug);
|
||||||
|
|
||||||
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
|
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
|
||||||
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
|
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
|
||||||
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c) << 2;
|
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c) << 2;
|
||||||
|
|
||||||
LOGV(BOOT, 1, "DVDRead: offset: %08x memOffse: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
LOGV(BOOT, 1, "DVDRead: offset: %08x memOffse: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
||||||
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
|
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
|
||||||
} while(PowerPC::ppcState.gpr[3] != 0x00);
|
} while(PowerPC::ppcState.gpr[3] != 0x00);
|
||||||
|
|
||||||
// iAppLoaderClose
|
// iAppLoaderClose
|
||||||
LOG(BOOT, "call iAppLoaderClose");
|
LOG(BOOT, "call iAppLoaderClose");
|
||||||
RunFunction(iAppLoaderClose, _bDebug);
|
RunFunction(iAppLoaderClose, _bDebug);
|
||||||
|
|
||||||
// Load patches and run startup patches
|
// Load patches and run startup patches
|
||||||
std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
|
std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
|
||||||
PatchEngine::LoadPatches(gameID.c_str());
|
PatchEngine::LoadPatches(gameID.c_str());
|
||||||
|
|
||||||
// return
|
// return
|
||||||
PC = PowerPC::ppcState.gpr[3];
|
PC = PowerPC::ppcState.gpr[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerPC::ppcState.DebugCount = 0;
|
PowerPC::ppcState.DebugCount = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,80 +1,80 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Boot_DOL.h"
|
#include "Boot_DOL.h"
|
||||||
|
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
|
|
||||||
CDolLoader::CDolLoader(const char* _szFilename) : m_bInit(false)
|
CDolLoader::CDolLoader(const char* _szFilename) : m_bInit(false)
|
||||||
{
|
{
|
||||||
// try to open file
|
// try to open file
|
||||||
FILE* pStream = fopen(_szFilename, "rb");
|
FILE* pStream = fopen(_szFilename, "rb");
|
||||||
if (pStream)
|
if (pStream)
|
||||||
{
|
{
|
||||||
fread(&m_dolheader, 1, sizeof(SDolHeader), pStream);
|
fread(&m_dolheader, 1, sizeof(SDolHeader), pStream);
|
||||||
|
|
||||||
// swap memory
|
// swap memory
|
||||||
u32* p = (u32*)&m_dolheader;
|
u32* p = (u32*)&m_dolheader;
|
||||||
for (size_t i=0; i<(sizeof(SDolHeader)>>2); i++)
|
for (size_t i=0; i<(sizeof(SDolHeader)>>2); i++)
|
||||||
p[i] = Common::swap32(p[i]);
|
p[i] = Common::swap32(p[i]);
|
||||||
|
|
||||||
// load all text (code) sections
|
// load all text (code) sections
|
||||||
for(int i = 0; i < DOL_NUM_TEXT; i++)
|
for(int i = 0; i < DOL_NUM_TEXT; i++)
|
||||||
{
|
{
|
||||||
if(m_dolheader.textOffset[i] != 0)
|
if(m_dolheader.textOffset[i] != 0)
|
||||||
{
|
{
|
||||||
u8* pTemp = new u8[m_dolheader.textSize[i]];
|
u8* pTemp = new u8[m_dolheader.textSize[i]];
|
||||||
|
|
||||||
fseek(pStream, m_dolheader.textOffset[i], SEEK_SET);
|
fseek(pStream, m_dolheader.textOffset[i], SEEK_SET);
|
||||||
fread(pTemp, 1, m_dolheader.textSize[i], pStream);
|
fread(pTemp, 1, m_dolheader.textSize[i], pStream);
|
||||||
|
|
||||||
for (u32 num = 0; num < m_dolheader.textSize[i]; num++)
|
for (u32 num = 0; num < m_dolheader.textSize[i]; num++)
|
||||||
Memory::Write_U8(pTemp[num], m_dolheader.textAddress[i] + num);
|
Memory::Write_U8(pTemp[num], m_dolheader.textAddress[i] + num);
|
||||||
|
|
||||||
delete [] pTemp;
|
delete [] pTemp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load all data sections
|
// load all data sections
|
||||||
for(int i = 0; i < DOL_NUM_DATA; i++)
|
for(int i = 0; i < DOL_NUM_DATA; i++)
|
||||||
{
|
{
|
||||||
if(m_dolheader.dataOffset[i] != 0)
|
if(m_dolheader.dataOffset[i] != 0)
|
||||||
{
|
{
|
||||||
u8* pTemp = new u8[m_dolheader.dataSize[i]];
|
u8* pTemp = new u8[m_dolheader.dataSize[i]];
|
||||||
|
|
||||||
fseek(pStream, m_dolheader.dataOffset[i], SEEK_SET);
|
fseek(pStream, m_dolheader.dataOffset[i], SEEK_SET);
|
||||||
fread(pTemp, 1, m_dolheader.dataSize[i], pStream);
|
fread(pTemp, 1, m_dolheader.dataSize[i], pStream);
|
||||||
|
|
||||||
for (u32 num = 0; num < m_dolheader.dataSize[i]; num++)
|
for (u32 num = 0; num < m_dolheader.dataSize[i]; num++)
|
||||||
Memory::Write_U8(pTemp[num], m_dolheader.dataAddress[i] + num);
|
Memory::Write_U8(pTemp[num], m_dolheader.dataAddress[i] + num);
|
||||||
|
|
||||||
delete [] pTemp;
|
delete [] pTemp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO - we know where there is code, and where there is data
|
//TODO - we know where there is code, and where there is data
|
||||||
//Make use of this!
|
//Make use of this!
|
||||||
|
|
||||||
fclose(pStream);
|
fclose(pStream);
|
||||||
m_bInit = true;
|
m_bInit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CDolLoader::GetEntryPoint()
|
u32 CDolLoader::GetEntryPoint()
|
||||||
{
|
{
|
||||||
return m_dolheader.entryPoint;
|
return m_dolheader.entryPoint;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,71 +1,71 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "Boot.h"
|
#include "Boot.h"
|
||||||
#include "../HLE/HLE.h"
|
#include "../HLE/HLE.h"
|
||||||
#include "Boot_ELF.h"
|
#include "Boot_ELF.h"
|
||||||
#include "ElfReader.h"
|
#include "ElfReader.h"
|
||||||
#include "MappedFile.h"
|
#include "MappedFile.h"
|
||||||
|
|
||||||
bool CBoot::IsElfWii(const char *filename)
|
bool CBoot::IsElfWii(const char *filename)
|
||||||
{
|
{
|
||||||
/* We already check if filename existed before we called this function, so
|
/* We already check if filename existed before we called this function, so
|
||||||
there is no need for another check, just read the file right away */
|
there is no need for another check, just read the file right away */
|
||||||
FILE *f = fopen(filename, "rb");
|
FILE *f = fopen(filename, "rb");
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
u64 filesize = ftell(f);
|
u64 filesize = ftell(f);
|
||||||
fseek(f, 0, SEEK_SET);
|
fseek(f, 0, SEEK_SET);
|
||||||
u8 *mem = new u8[(size_t)filesize];
|
u8 *mem = new u8[(size_t)filesize];
|
||||||
fread(mem, 1, filesize, f);
|
fread(mem, 1, filesize, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
ElfReader reader(mem);
|
ElfReader reader(mem);
|
||||||
// TODO: Find a more reliable way to distinguish.
|
// TODO: Find a more reliable way to distinguish.
|
||||||
bool isWii = reader.GetEntryPoint() >= 0x80004000;
|
bool isWii = reader.GetEntryPoint() >= 0x80004000;
|
||||||
delete [] mem;
|
delete [] mem;
|
||||||
|
|
||||||
return isWii;
|
return isWii;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CBoot::Boot_ELF(const char *filename)
|
bool CBoot::Boot_ELF(const char *filename)
|
||||||
{
|
{
|
||||||
FILE *f = fopen(filename, "rb");
|
FILE *f = fopen(filename, "rb");
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
u64 filesize = ftell(f);
|
u64 filesize = ftell(f);
|
||||||
fseek(f, 0, SEEK_SET);
|
fseek(f, 0, SEEK_SET);
|
||||||
u8 *mem = new u8[(size_t)filesize];
|
u8 *mem = new u8[(size_t)filesize];
|
||||||
fread(mem, 1, filesize, f);
|
fread(mem, 1, filesize, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
ElfReader reader(mem);
|
ElfReader reader(mem);
|
||||||
reader.LoadInto(0x80000000);
|
reader.LoadInto(0x80000000);
|
||||||
if (!reader.LoadSymbols())
|
if (!reader.LoadSymbols())
|
||||||
{
|
{
|
||||||
if (LoadMapFromFilename(filename))
|
if (LoadMapFromFilename(filename))
|
||||||
HLE::PatchFunctions();
|
HLE::PatchFunctions();
|
||||||
} else {
|
} else {
|
||||||
HLE::PatchFunctions();
|
HLE::PatchFunctions();
|
||||||
}
|
}
|
||||||
|
|
||||||
PC = reader.GetEntryPoint();
|
PC = reader.GetEntryPoint();
|
||||||
delete [] mem;
|
delete [] mem;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,258 +1,258 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "../Debugger/Debugger_SymbolMap.h"
|
#include "../Debugger/Debugger_SymbolMap.h"
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
#include "../PowerPC/SymbolDB.h"
|
#include "../PowerPC/SymbolDB.h"
|
||||||
#include "ElfReader.h"
|
#include "ElfReader.h"
|
||||||
|
|
||||||
void bswap(Elf32_Word &w) {w = Common::swap32(w);}
|
void bswap(Elf32_Word &w) {w = Common::swap32(w);}
|
||||||
void bswap(Elf32_Half &w) {w = Common::swap16(w);}
|
void bswap(Elf32_Half &w) {w = Common::swap16(w);}
|
||||||
|
|
||||||
void byteswapHeader(Elf32_Ehdr &ELF_H)
|
void byteswapHeader(Elf32_Ehdr &ELF_H)
|
||||||
{
|
{
|
||||||
bswap(ELF_H.e_type);
|
bswap(ELF_H.e_type);
|
||||||
bswap(ELF_H.e_machine);
|
bswap(ELF_H.e_machine);
|
||||||
bswap(ELF_H.e_ehsize);
|
bswap(ELF_H.e_ehsize);
|
||||||
bswap(ELF_H.e_phentsize);
|
bswap(ELF_H.e_phentsize);
|
||||||
bswap(ELF_H.e_phnum);
|
bswap(ELF_H.e_phnum);
|
||||||
bswap(ELF_H.e_shentsize);
|
bswap(ELF_H.e_shentsize);
|
||||||
bswap(ELF_H.e_shnum);
|
bswap(ELF_H.e_shnum);
|
||||||
bswap(ELF_H.e_shstrndx);
|
bswap(ELF_H.e_shstrndx);
|
||||||
bswap(ELF_H.e_version);
|
bswap(ELF_H.e_version);
|
||||||
bswap(ELF_H.e_entry);
|
bswap(ELF_H.e_entry);
|
||||||
bswap(ELF_H.e_phoff);
|
bswap(ELF_H.e_phoff);
|
||||||
bswap(ELF_H.e_shoff);
|
bswap(ELF_H.e_shoff);
|
||||||
bswap(ELF_H.e_flags);
|
bswap(ELF_H.e_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void byteswapSegment(Elf32_Phdr &sec)
|
void byteswapSegment(Elf32_Phdr &sec)
|
||||||
{
|
{
|
||||||
bswap(sec.p_align);
|
bswap(sec.p_align);
|
||||||
bswap(sec.p_filesz);
|
bswap(sec.p_filesz);
|
||||||
bswap(sec.p_flags);
|
bswap(sec.p_flags);
|
||||||
bswap(sec.p_memsz);
|
bswap(sec.p_memsz);
|
||||||
bswap(sec.p_offset);
|
bswap(sec.p_offset);
|
||||||
bswap(sec.p_paddr);
|
bswap(sec.p_paddr);
|
||||||
bswap(sec.p_vaddr);
|
bswap(sec.p_vaddr);
|
||||||
bswap(sec.p_type);
|
bswap(sec.p_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void byteswapSection(Elf32_Shdr &sec)
|
void byteswapSection(Elf32_Shdr &sec)
|
||||||
{
|
{
|
||||||
bswap(sec.sh_addr);
|
bswap(sec.sh_addr);
|
||||||
bswap(sec.sh_addralign);
|
bswap(sec.sh_addralign);
|
||||||
bswap(sec.sh_entsize);
|
bswap(sec.sh_entsize);
|
||||||
bswap(sec.sh_flags);
|
bswap(sec.sh_flags);
|
||||||
bswap(sec.sh_info);
|
bswap(sec.sh_info);
|
||||||
bswap(sec.sh_link);
|
bswap(sec.sh_link);
|
||||||
bswap(sec.sh_name);
|
bswap(sec.sh_name);
|
||||||
bswap(sec.sh_offset);
|
bswap(sec.sh_offset);
|
||||||
bswap(sec.sh_size);
|
bswap(sec.sh_size);
|
||||||
bswap(sec.sh_type);
|
bswap(sec.sh_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ElfReader::ElfReader(void *ptr)
|
ElfReader::ElfReader(void *ptr)
|
||||||
{
|
{
|
||||||
base = (char*)ptr;
|
base = (char*)ptr;
|
||||||
base32 = (u32 *)ptr;
|
base32 = (u32 *)ptr;
|
||||||
header = (Elf32_Ehdr*)ptr;
|
header = (Elf32_Ehdr*)ptr;
|
||||||
byteswapHeader(*header);
|
byteswapHeader(*header);
|
||||||
|
|
||||||
segments = (Elf32_Phdr *)(base + header->e_phoff);
|
segments = (Elf32_Phdr *)(base + header->e_phoff);
|
||||||
sections = (Elf32_Shdr *)(base + header->e_shoff);
|
sections = (Elf32_Shdr *)(base + header->e_shoff);
|
||||||
|
|
||||||
for (int i = 0; i < GetNumSegments(); i++)
|
for (int i = 0; i < GetNumSegments(); i++)
|
||||||
{
|
{
|
||||||
byteswapSegment(segments[i]);
|
byteswapSegment(segments[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < GetNumSections(); i++)
|
for (int i = 0; i < GetNumSections(); i++)
|
||||||
{
|
{
|
||||||
byteswapSection(sections[i]);
|
byteswapSection(sections[i]);
|
||||||
}
|
}
|
||||||
entryPoint = header->e_entry;
|
entryPoint = header->e_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *ElfReader::GetSectionName(int section) const
|
const char *ElfReader::GetSectionName(int section) const
|
||||||
{
|
{
|
||||||
if (sections[section].sh_type == SHT_NULL)
|
if (sections[section].sh_type == SHT_NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int nameOffset = sections[section].sh_name;
|
int nameOffset = sections[section].sh_name;
|
||||||
char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx);
|
char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx);
|
||||||
|
|
||||||
if (ptr)
|
if (ptr)
|
||||||
return ptr + nameOffset;
|
return ptr + nameOffset;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addrToHiLo(u32 addr, u16 &hi, s16 &lo)
|
void addrToHiLo(u32 addr, u16 &hi, s16 &lo)
|
||||||
{
|
{
|
||||||
lo = (addr & 0xFFFF);
|
lo = (addr & 0xFFFF);
|
||||||
u32 naddr = addr - lo;
|
u32 naddr = addr - lo;
|
||||||
hi = naddr>>16;
|
hi = naddr>>16;
|
||||||
|
|
||||||
u32 test = (hi<<16) + lo;
|
u32 test = (hi<<16) + lo;
|
||||||
if (test != addr)
|
if (test != addr)
|
||||||
{
|
{
|
||||||
Crash();
|
Crash();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ElfReader::LoadInto(u32 vaddr)
|
bool ElfReader::LoadInto(u32 vaddr)
|
||||||
{
|
{
|
||||||
LOG(MASTER_LOG,"String section: %i", header->e_shstrndx);
|
LOG(MASTER_LOG,"String section: %i", header->e_shstrndx);
|
||||||
|
|
||||||
// sectionOffsets = new u32[GetNumSections()];
|
// sectionOffsets = new u32[GetNumSections()];
|
||||||
// sectionAddrs = new u32[GetNumSections()];
|
// sectionAddrs = new u32[GetNumSections()];
|
||||||
|
|
||||||
// Should we relocate?
|
// Should we relocate?
|
||||||
bRelocate = (header->e_type != ET_EXEC);
|
bRelocate = (header->e_type != ET_EXEC);
|
||||||
|
|
||||||
if (bRelocate)
|
if (bRelocate)
|
||||||
{
|
{
|
||||||
LOG(MASTER_LOG,"Relocatable module");
|
LOG(MASTER_LOG,"Relocatable module");
|
||||||
entryPoint += vaddr;
|
entryPoint += vaddr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(MASTER_LOG,"Prerelocated executable");
|
LOG(MASTER_LOG,"Prerelocated executable");
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(MASTER_LOG,"%i segments:", header->e_phnum);
|
LOG(MASTER_LOG,"%i segments:", header->e_phnum);
|
||||||
|
|
||||||
// First pass : Get the bits into RAM
|
// First pass : Get the bits into RAM
|
||||||
u32 segmentVAddr[32];
|
u32 segmentVAddr[32];
|
||||||
|
|
||||||
u32 baseAddress = bRelocate?vaddr:0;
|
u32 baseAddress = bRelocate?vaddr:0;
|
||||||
for (int i = 0; i < header->e_phnum; i++)
|
for (int i = 0; i < header->e_phnum; i++)
|
||||||
{
|
{
|
||||||
Elf32_Phdr *p = segments + i;
|
Elf32_Phdr *p = segments + i;
|
||||||
|
|
||||||
LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz);
|
LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz);
|
||||||
|
|
||||||
if (p->p_type == PT_LOAD)
|
if (p->p_type == PT_LOAD)
|
||||||
{
|
{
|
||||||
segmentVAddr[i] = baseAddress + p->p_vaddr;
|
segmentVAddr[i] = baseAddress + p->p_vaddr;
|
||||||
u32 writeAddr = segmentVAddr[i];
|
u32 writeAddr = segmentVAddr[i];
|
||||||
|
|
||||||
const u8 *src = GetSegmentPtr(i);
|
const u8 *src = GetSegmentPtr(i);
|
||||||
u8 *dst = Memory::GetPointer(writeAddr);
|
u8 *dst = Memory::GetPointer(writeAddr);
|
||||||
u32 srcSize = p->p_filesz;
|
u32 srcSize = p->p_filesz;
|
||||||
u32 dstSize = p->p_memsz;
|
u32 dstSize = p->p_memsz;
|
||||||
u32 *s = (u32*)src;
|
u32 *s = (u32*)src;
|
||||||
u32 *d = (u32*)dst;
|
u32 *d = (u32*)dst;
|
||||||
for (int j = 0; j < (int)(srcSize + 3) / 4; j++)
|
for (int j = 0; j < (int)(srcSize + 3) / 4; j++)
|
||||||
{
|
{
|
||||||
*d++ = /*_byteswap_ulong*/(*s++);
|
*d++ = /*_byteswap_ulong*/(*s++);
|
||||||
}
|
}
|
||||||
if (srcSize < dstSize)
|
if (srcSize < dstSize)
|
||||||
{
|
{
|
||||||
//memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss
|
//memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss
|
||||||
}
|
}
|
||||||
LOG(MASTER_LOG,"Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz);
|
LOG(MASTER_LOG,"Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
LOG(MASTER_LOG,"%i sections:", header->e_shnum);
|
LOG(MASTER_LOG,"%i sections:", header->e_shnum);
|
||||||
|
|
||||||
for (int i=0; i<GetNumSections(); i++)
|
for (int i=0; i<GetNumSections(); i++)
|
||||||
{
|
{
|
||||||
Elf32_Shdr *s = §ions[i];
|
Elf32_Shdr *s = §ions[i];
|
||||||
const char *name = GetSectionName(i);
|
const char *name = GetSectionName(i);
|
||||||
|
|
||||||
u32 writeAddr = s->sh_addr + baseAddress;
|
u32 writeAddr = s->sh_addr + baseAddress;
|
||||||
sectionOffsets[i] = writeAddr - vaddr;
|
sectionOffsets[i] = writeAddr - vaddr;
|
||||||
sectionAddrs[i] = writeAddr;
|
sectionAddrs[i] = writeAddr;
|
||||||
|
|
||||||
if (s->sh_flags & SHF_ALLOC)
|
if (s->sh_flags & SHF_ALLOC)
|
||||||
{
|
{
|
||||||
LOG(MASTER_LOG,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, s->sh_size);
|
LOG(MASTER_LOG,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, s->sh_size);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(MASTER_LOG,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, s->sh_size, s->sh_flags);
|
LOG(MASTER_LOG,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, s->sh_size, s->sh_flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
LOG(MASTER_LOG,"Done.");
|
LOG(MASTER_LOG,"Done.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const
|
SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const
|
||||||
{
|
{
|
||||||
for (int i = firstSection; i < header->e_shnum; i++)
|
for (int i = firstSection; i < header->e_shnum; i++)
|
||||||
{
|
{
|
||||||
const char *secname = GetSectionName(i);
|
const char *secname = GetSectionName(i);
|
||||||
|
|
||||||
if (secname != 0 && strcmp(name, secname) == 0)
|
if (secname != 0 && strcmp(name, secname) == 0)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ElfReader::LoadSymbols()
|
bool ElfReader::LoadSymbols()
|
||||||
{
|
{
|
||||||
bool hasSymbols = false;
|
bool hasSymbols = false;
|
||||||
SectionID sec = GetSectionByName(".symtab");
|
SectionID sec = GetSectionByName(".symtab");
|
||||||
if (sec != -1)
|
if (sec != -1)
|
||||||
{
|
{
|
||||||
int stringSection = sections[sec].sh_link;
|
int stringSection = sections[sec].sh_link;
|
||||||
const char *stringBase = (const char *)GetSectionDataPtr(stringSection);
|
const char *stringBase = (const char *)GetSectionDataPtr(stringSection);
|
||||||
|
|
||||||
//We have a symbol table!
|
//We have a symbol table!
|
||||||
Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
|
Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
|
||||||
int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
|
int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
|
||||||
for (int sym = 0; sym < numSymbols; sym++)
|
for (int sym = 0; sym < numSymbols; sym++)
|
||||||
{
|
{
|
||||||
int size = Common::swap32(symtab[sym].st_size);
|
int size = Common::swap32(symtab[sym].st_size);
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// int bind = symtab[sym].st_info >> 4;
|
// int bind = symtab[sym].st_info >> 4;
|
||||||
int type = symtab[sym].st_info & 0xF;
|
int type = symtab[sym].st_info & 0xF;
|
||||||
int sectionIndex = Common::swap16(symtab[sym].st_shndx);
|
int sectionIndex = Common::swap16(symtab[sym].st_shndx);
|
||||||
int value = Common::swap32(symtab[sym].st_value);
|
int value = Common::swap32(symtab[sym].st_value);
|
||||||
const char *name = stringBase + Common::swap32(symtab[sym].st_name);
|
const char *name = stringBase + Common::swap32(symtab[sym].st_name);
|
||||||
if (bRelocate)
|
if (bRelocate)
|
||||||
value += sectionAddrs[sectionIndex];
|
value += sectionAddrs[sectionIndex];
|
||||||
|
|
||||||
int symtype = Symbol::SYMBOL_DATA;
|
int symtype = Symbol::SYMBOL_DATA;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case STT_OBJECT:
|
case STT_OBJECT:
|
||||||
symtype = Symbol::SYMBOL_DATA; break;
|
symtype = Symbol::SYMBOL_DATA; break;
|
||||||
case STT_FUNC:
|
case STT_FUNC:
|
||||||
symtype = Symbol::SYMBOL_FUNCTION; break;
|
symtype = Symbol::SYMBOL_FUNCTION; break;
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
g_symbolDB.AddKnownSymbol(value, size, name, symtype);
|
g_symbolDB.AddKnownSymbol(value, size, name, symtype);
|
||||||
hasSymbols = true;
|
hasSymbols = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_symbolDB.Index();
|
g_symbolDB.Index();
|
||||||
return hasSymbols;
|
return hasSymbols;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,160 +1,160 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "HW/Memmap.h"
|
#include "HW/Memmap.h"
|
||||||
#include "PowerPC/PPCAnalyst.h"
|
#include "PowerPC/PPCAnalyst.h"
|
||||||
#include "PowerPC/PPCTables.h"
|
#include "PowerPC/PPCTables.h"
|
||||||
#include "CoreTiming.h"
|
#include "CoreTiming.h"
|
||||||
#include "Core.h"
|
#include "Core.h"
|
||||||
#include "PowerPC/Jit64/JitCache.h"
|
#include "PowerPC/Jit64/JitCache.h"
|
||||||
#include "PowerPC/SymbolDB.h"
|
#include "PowerPC/SymbolDB.h"
|
||||||
#include "PowerPCDisasm.h"
|
#include "PowerPCDisasm.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
|
|
||||||
#define CASE(x) else if (memcmp(cmd, x, 4*sizeof(TCHAR))==0)
|
#define CASE(x) else if (memcmp(cmd, x, 4*sizeof(TCHAR))==0)
|
||||||
#define CASE1(x) if (memcmp(cmd, x, 2*sizeof(TCHAR))==0)
|
#define CASE1(x) if (memcmp(cmd, x, 2*sizeof(TCHAR))==0)
|
||||||
|
|
||||||
void Console_Submit(const char *cmd)
|
void Console_Submit(const char *cmd)
|
||||||
{
|
{
|
||||||
CASE1("jits")
|
CASE1("jits")
|
||||||
{
|
{
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
Jit64::PrintStats();
|
Jit64::PrintStats();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
CASE1("r")
|
CASE1("r")
|
||||||
{
|
{
|
||||||
Core::StartTrace(false);
|
Core::StartTrace(false);
|
||||||
LOG(CONSOLE, "read tracing started.");
|
LOG(CONSOLE, "read tracing started.");
|
||||||
}
|
}
|
||||||
CASE1("w")
|
CASE1("w")
|
||||||
{
|
{
|
||||||
Core::StartTrace(true);
|
Core::StartTrace(true);
|
||||||
LOG(CONSOLE, "write tracing started.");
|
LOG(CONSOLE, "write tracing started.");
|
||||||
}
|
}
|
||||||
CASE("trans")
|
CASE("trans")
|
||||||
{
|
{
|
||||||
TCHAR temp[256];
|
TCHAR temp[256];
|
||||||
u32 addr;
|
u32 addr;
|
||||||
sscanf(cmd, "%s %08x", temp, &addr);
|
sscanf(cmd, "%s %08x", temp, &addr);
|
||||||
|
|
||||||
if (addr!=0)
|
if (addr!=0)
|
||||||
{
|
{
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
u32 EA =
|
u32 EA =
|
||||||
#endif
|
#endif
|
||||||
Memory::CheckDTLB(addr, Memory::FLAG_NO_EXCEPTION);
|
Memory::CheckDTLB(addr, Memory::FLAG_NO_EXCEPTION);
|
||||||
LOG(CONSOLE, "EA 0x%08x to 0x%08x", addr, EA);
|
LOG(CONSOLE, "EA 0x%08x to 0x%08x", addr, EA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(CONSOLE, "Syntax: trans ADDR");
|
LOG(CONSOLE, "Syntax: trans ADDR");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE("call")
|
CASE("call")
|
||||||
{
|
{
|
||||||
TCHAR temp[256];
|
TCHAR temp[256];
|
||||||
u32 addr;
|
u32 addr;
|
||||||
sscanf(cmd, "%s %08x", temp, &addr);
|
sscanf(cmd, "%s %08x", temp, &addr);
|
||||||
if (addr!=0)
|
if (addr!=0)
|
||||||
{
|
{
|
||||||
g_symbolDB.PrintCalls(addr);
|
g_symbolDB.PrintCalls(addr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(CONSOLE, "Syntax: call ADDR");
|
LOG(CONSOLE, "Syntax: call ADDR");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE("llac")
|
CASE("llac")
|
||||||
{
|
{
|
||||||
TCHAR temp[256];
|
TCHAR temp[256];
|
||||||
u32 addr;
|
u32 addr;
|
||||||
sscanf(cmd, "%s %08x", temp, &addr);
|
sscanf(cmd, "%s %08x", temp, &addr);
|
||||||
if (addr!=0)
|
if (addr!=0)
|
||||||
{
|
{
|
||||||
g_symbolDB.PrintCallers(addr);
|
g_symbolDB.PrintCallers(addr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(CONSOLE, "Syntax: llac ADDR");
|
LOG(CONSOLE, "Syntax: llac ADDR");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE("pend")
|
CASE("pend")
|
||||||
{
|
{
|
||||||
CoreTiming::LogPendingEvents();
|
CoreTiming::LogPendingEvents();
|
||||||
}
|
}
|
||||||
CASE("dump")
|
CASE("dump")
|
||||||
{
|
{
|
||||||
TCHAR temp[256];
|
TCHAR temp[256];
|
||||||
TCHAR filename[256];
|
TCHAR filename[256];
|
||||||
u32 start;
|
u32 start;
|
||||||
u32 end;
|
u32 end;
|
||||||
sscanf(cmd, "%s %08x %08x %s", temp, &start, &end, filename);
|
sscanf(cmd, "%s %08x %08x %s", temp, &start, &end, filename);
|
||||||
|
|
||||||
FILE *f = fopen(filename, "wb");
|
FILE *f = fopen(filename, "wb");
|
||||||
for (u32 i=start; i<end; i++)
|
for (u32 i=start; i<end; i++)
|
||||||
{
|
{
|
||||||
u8 b = Memory::ReadUnchecked_U8(i);
|
u8 b = Memory::ReadUnchecked_U8(i);
|
||||||
fputc(b,f);
|
fputc(b,f);
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
LOG(CONSOLE, "Dumped from %08x to %08x to %s",start,end,filename);
|
LOG(CONSOLE, "Dumped from %08x to %08x to %s",start,end,filename);
|
||||||
}
|
}
|
||||||
CASE("disa")
|
CASE("disa")
|
||||||
{
|
{
|
||||||
u32 start;
|
u32 start;
|
||||||
u32 end;
|
u32 end;
|
||||||
TCHAR temp[256];
|
TCHAR temp[256];
|
||||||
sscanf(cmd, "%s %08x %08x", temp, &start, &end);
|
sscanf(cmd, "%s %08x %08x", temp, &start, &end);
|
||||||
for (u32 addr = start; addr <= end; addr += 4) {
|
for (u32 addr = start; addr <= end; addr += 4) {
|
||||||
u32 data = Memory::ReadUnchecked_U32(addr);
|
u32 data = Memory::ReadUnchecked_U32(addr);
|
||||||
printf("%08x: %08x: %s\n", addr, data, DisassembleGekko(data, addr));
|
printf("%08x: %08x: %s\n", addr, data, DisassembleGekko(data, addr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE("help")
|
CASE("help")
|
||||||
{
|
{
|
||||||
LOG(CONSOLE, "Dolphin Console Command List");
|
LOG(CONSOLE, "Dolphin Console Command List");
|
||||||
LOG(CONSOLE, "scan ADDR - will find functions that are called by this function");
|
LOG(CONSOLE, "scan ADDR - will find functions that are called by this function");
|
||||||
LOG(CONSOLE, "call ADDR - will find functions that call this function");
|
LOG(CONSOLE, "call ADDR - will find functions that call this function");
|
||||||
LOG(CONSOLE, "dump START_A END_A FILENAME - will dump memory between START_A and END_A");
|
LOG(CONSOLE, "dump START_A END_A FILENAME - will dump memory between START_A and END_A");
|
||||||
LOG(CONSOLE, "help - guess what this does :P");
|
LOG(CONSOLE, "help - guess what this does :P");
|
||||||
LOG(CONSOLE, "lisd - list signature database");
|
LOG(CONSOLE, "lisd - list signature database");
|
||||||
LOG(CONSOLE, "lisf - list functions");
|
LOG(CONSOLE, "lisf - list functions");
|
||||||
LOG(CONSOLE, "trans ADDR - translate address");
|
LOG(CONSOLE, "trans ADDR - translate address");
|
||||||
}
|
}
|
||||||
CASE("lisd")
|
CASE("lisd")
|
||||||
{
|
{
|
||||||
// PPCAnalyst::ListDB();
|
// PPCAnalyst::ListDB();
|
||||||
}
|
}
|
||||||
CASE("ipro")
|
CASE("ipro")
|
||||||
{
|
{
|
||||||
PPCTables::PrintInstructionRunCounts();
|
PPCTables::PrintInstructionRunCounts();
|
||||||
}
|
}
|
||||||
CASE("lisf")
|
CASE("lisf")
|
||||||
{
|
{
|
||||||
g_symbolDB.List();
|
g_symbolDB.List();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf("blach\n");
|
printf("blach\n");
|
||||||
LOG(CONSOLE, "Invalid command");
|
LOG(CONSOLE, "Invalid command");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,160 +1,160 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Boot/Boot.h"
|
#include "Boot/Boot.h"
|
||||||
#include "FileUtil.h"
|
#include "FileUtil.h"
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "CoreParameter.h"
|
#include "CoreParameter.h"
|
||||||
#include "VolumeCreator.h"
|
#include "VolumeCreator.h"
|
||||||
|
|
||||||
SCoreStartupParameter::SCoreStartupParameter()
|
SCoreStartupParameter::SCoreStartupParameter()
|
||||||
{
|
{
|
||||||
LoadDefaults();
|
LoadDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SCoreStartupParameter::LoadDefaults()
|
void SCoreStartupParameter::LoadDefaults()
|
||||||
{
|
{
|
||||||
bEnableDebugging = false;
|
bEnableDebugging = false;
|
||||||
bUseJIT = false;
|
bUseJIT = false;
|
||||||
bUseDualCore = false;
|
bUseDualCore = false;
|
||||||
bSkipIdle = false;
|
bSkipIdle = false;
|
||||||
bRunCompareServer = false;
|
bRunCompareServer = false;
|
||||||
bLockThreads = true;
|
bLockThreads = true;
|
||||||
bWii = false;
|
bWii = false;
|
||||||
SelectedLanguage = 0;
|
SelectedLanguage = 0;
|
||||||
|
|
||||||
bJITOff = false; // debugger only settings
|
bJITOff = false; // debugger only settings
|
||||||
bJITLoadStoreOff = false;
|
bJITLoadStoreOff = false;
|
||||||
bJITLoadStoreFloatingOff = false;
|
bJITLoadStoreFloatingOff = false;
|
||||||
bJITLoadStorePairedOff = false;
|
bJITLoadStorePairedOff = false;
|
||||||
bJITFloatingPointOff = false;
|
bJITFloatingPointOff = false;
|
||||||
bJITIntegerOff = false;
|
bJITIntegerOff = false;
|
||||||
bJITPairedOff = false;
|
bJITPairedOff = false;
|
||||||
bJITSystemRegistersOff = false;
|
bJITSystemRegistersOff = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SCoreStartupParameter::AutoSetup(EBootBios _BootBios)
|
bool SCoreStartupParameter::AutoSetup(EBootBios _BootBios)
|
||||||
{
|
{
|
||||||
std::string Region(EUR_DIR);
|
std::string Region(EUR_DIR);
|
||||||
|
|
||||||
switch (_BootBios)
|
switch (_BootBios)
|
||||||
{
|
{
|
||||||
case BOOT_DEFAULT:
|
case BOOT_DEFAULT:
|
||||||
{
|
{
|
||||||
/* Check if the file exist, we may have gotten it from a --elf command line
|
/* Check if the file exist, we may have gotten it from a --elf command line
|
||||||
that gave an incorrect file name */
|
that gave an incorrect file name */
|
||||||
if (!File::Exists(m_strFilename.c_str()))
|
if (!File::Exists(m_strFilename.c_str()))
|
||||||
{
|
{
|
||||||
PanicAlert("The file you specified (%s) does not exists", m_strFilename.c_str());
|
PanicAlert("The file you specified (%s) does not exists", m_strFilename.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Extension;
|
std::string Extension;
|
||||||
SplitPath(m_strFilename, NULL, NULL, &Extension);
|
SplitPath(m_strFilename, NULL, NULL, &Extension);
|
||||||
if (!strcasecmp(Extension.c_str(), ".gcm") ||
|
if (!strcasecmp(Extension.c_str(), ".gcm") ||
|
||||||
!strcasecmp(Extension.c_str(), ".iso") ||
|
!strcasecmp(Extension.c_str(), ".iso") ||
|
||||||
!strcasecmp(Extension.c_str(), ".gcz") )
|
!strcasecmp(Extension.c_str(), ".gcz") )
|
||||||
{
|
{
|
||||||
m_BootType = BOOT_ISO;
|
m_BootType = BOOT_ISO;
|
||||||
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(m_strFilename.c_str());
|
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(m_strFilename.c_str());
|
||||||
if (pVolume == NULL)
|
if (pVolume == NULL)
|
||||||
{
|
{
|
||||||
PanicAlert("Your GCM/ISO file seems to be invalid, or not a GC/Wii ISO.");
|
PanicAlert("Your GCM/ISO file seems to be invalid, or not a GC/Wii ISO.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_strName = pVolume->GetName();
|
m_strName = pVolume->GetName();
|
||||||
m_strUniqueID = pVolume->GetUniqueID();
|
m_strUniqueID = pVolume->GetUniqueID();
|
||||||
bWii = DiscIO::IsVolumeWiiDisc(pVolume);
|
bWii = DiscIO::IsVolumeWiiDisc(pVolume);
|
||||||
|
|
||||||
switch (pVolume->GetCountry())
|
switch (pVolume->GetCountry())
|
||||||
{
|
{
|
||||||
case DiscIO::IVolume::COUNTRY_USA:
|
case DiscIO::IVolume::COUNTRY_USA:
|
||||||
bNTSC = true;
|
bNTSC = true;
|
||||||
Region = USA_DIR;
|
Region = USA_DIR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DiscIO::IVolume::COUNTRY_JAP:
|
case DiscIO::IVolume::COUNTRY_JAP:
|
||||||
bNTSC = true;
|
bNTSC = true;
|
||||||
Region = JAP_DIR;
|
Region = JAP_DIR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DiscIO::IVolume::COUNTRY_EUROPE:
|
case DiscIO::IVolume::COUNTRY_EUROPE:
|
||||||
case DiscIO::IVolume::COUNTRY_FRANCE:
|
case DiscIO::IVolume::COUNTRY_FRANCE:
|
||||||
bNTSC = false;
|
bNTSC = false;
|
||||||
Region = EUR_DIR;
|
Region = EUR_DIR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PanicAlert("Your GCM/ISO file seems to be invalid (invalid country).");
|
PanicAlert("Your GCM/ISO file seems to be invalid (invalid country).");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete pVolume;
|
delete pVolume;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(Extension.c_str(), ".elf"))
|
else if (!strcasecmp(Extension.c_str(), ".elf"))
|
||||||
{
|
{
|
||||||
bWii = CBoot::IsElfWii(m_strFilename.c_str());
|
bWii = CBoot::IsElfWii(m_strFilename.c_str());
|
||||||
Region = USA_DIR;
|
Region = USA_DIR;
|
||||||
m_BootType = BOOT_ELF;
|
m_BootType = BOOT_ELF;
|
||||||
bNTSC = true;
|
bNTSC = true;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(Extension.c_str(), ".dol"))
|
else if (!strcasecmp(Extension.c_str(), ".dol"))
|
||||||
{
|
{
|
||||||
Region = USA_DIR;
|
Region = USA_DIR;
|
||||||
m_BootType = BOOT_DOL;
|
m_BootType = BOOT_DOL;
|
||||||
bNTSC = true;
|
bNTSC = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PanicAlert("Could not recognize ISO file %s", m_strFilename.c_str());
|
PanicAlert("Could not recognize ISO file %s", m_strFilename.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BOOT_BIOS_USA:
|
case BOOT_BIOS_USA:
|
||||||
Region = USA_DIR;
|
Region = USA_DIR;
|
||||||
m_strFilename.clear();
|
m_strFilename.clear();
|
||||||
bNTSC = true;
|
bNTSC = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BOOT_BIOS_JAP:
|
case BOOT_BIOS_JAP:
|
||||||
Region = JAP_DIR;
|
Region = JAP_DIR;
|
||||||
m_strFilename.clear();
|
m_strFilename.clear();
|
||||||
bNTSC = true;
|
bNTSC = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BOOT_BIOS_EUR:
|
case BOOT_BIOS_EUR:
|
||||||
Region = EUR_DIR;
|
Region = EUR_DIR;
|
||||||
m_strFilename.clear();
|
m_strFilename.clear();
|
||||||
bNTSC = false;
|
bNTSC = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup paths
|
// setup paths
|
||||||
m_strBios = FULL_GC_SYS_DIR + Region + DIR_SEP GC_IPL;
|
m_strBios = FULL_GC_SYS_DIR + Region + DIR_SEP GC_IPL;
|
||||||
m_strMemoryCardA = FULL_GC_USER_DIR + Region + DIR_SEP GC_MEMCARDA;
|
m_strMemoryCardA = FULL_GC_USER_DIR + Region + DIR_SEP GC_MEMCARDA;
|
||||||
m_strMemoryCardB = FULL_GC_USER_DIR + Region + DIR_SEP GC_MEMCARDB;
|
m_strMemoryCardB = FULL_GC_USER_DIR + Region + DIR_SEP GC_MEMCARDB;
|
||||||
m_strSRAM = GC_SRAM_FILE;
|
m_strSRAM = GC_SRAM_FILE;
|
||||||
if (!File::Exists(m_strBios.c_str())) {
|
if (!File::Exists(m_strBios.c_str())) {
|
||||||
LOG(BOOT, "BIOS file %s not found - using HLE.", m_strBios.c_str());
|
LOG(BOOT, "BIOS file %s not found - using HLE.", m_strBios.c_str());
|
||||||
bHLEBios = true;
|
bHLEBios = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,377 +1,377 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "PowerPC/PowerPC.h"
|
#include "PowerPC/PowerPC.h"
|
||||||
#include "CoreTiming.h"
|
#include "CoreTiming.h"
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
|
|
||||||
// TODO(ector): Replace new/delete in this file with a simple memory pool
|
// TODO(ector): Replace new/delete in this file with a simple memory pool
|
||||||
// Don't expect a massive speedup though.
|
// Don't expect a massive speedup though.
|
||||||
|
|
||||||
namespace CoreTiming
|
namespace CoreTiming
|
||||||
{
|
{
|
||||||
|
|
||||||
struct EventType
|
struct EventType
|
||||||
{
|
{
|
||||||
TimedCallback callback;
|
TimedCallback callback;
|
||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<EventType> event_types;
|
std::vector<EventType> event_types;
|
||||||
|
|
||||||
struct BaseEvent
|
struct BaseEvent
|
||||||
{
|
{
|
||||||
s64 time;
|
s64 time;
|
||||||
u64 userdata;
|
u64 userdata;
|
||||||
int type;
|
int type;
|
||||||
// Event *next;
|
// Event *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef LinkedListItem<BaseEvent> Event;
|
typedef LinkedListItem<BaseEvent> Event;
|
||||||
|
|
||||||
// STATE_TO_SAVE (how?)
|
// STATE_TO_SAVE (how?)
|
||||||
Event *first;
|
Event *first;
|
||||||
Event *tsFirst;
|
Event *tsFirst;
|
||||||
|
|
||||||
int downcount, slicelength;
|
int downcount, slicelength;
|
||||||
int maxSliceLength = 20000;
|
int maxSliceLength = 20000;
|
||||||
|
|
||||||
s64 globalTimer;
|
s64 globalTimer;
|
||||||
s64 idledCycles;
|
s64 idledCycles;
|
||||||
|
|
||||||
Common::CriticalSection externalEventSection;
|
Common::CriticalSection externalEventSection;
|
||||||
|
|
||||||
void (*advanceCallback)(int cyclesExecuted);
|
void (*advanceCallback)(int cyclesExecuted);
|
||||||
|
|
||||||
int RegisterEvent(const char *name, TimedCallback callback)
|
int RegisterEvent(const char *name, TimedCallback callback)
|
||||||
{
|
{
|
||||||
EventType type;
|
EventType type;
|
||||||
type.name = name;
|
type.name = name;
|
||||||
type.callback = callback;
|
type.callback = callback;
|
||||||
event_types.push_back(type);
|
event_types.push_back(type);
|
||||||
return (int)event_types.size() - 1;
|
return (int)event_types.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnregisterAllEvents()
|
void UnregisterAllEvents()
|
||||||
{
|
{
|
||||||
if (first)
|
if (first)
|
||||||
PanicAlert("Cannot unregister events with events pending");
|
PanicAlert("Cannot unregister events with events pending");
|
||||||
event_types.clear();
|
event_types.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
downcount = maxSliceLength;
|
downcount = maxSliceLength;
|
||||||
slicelength = maxSliceLength;
|
slicelength = maxSliceLength;
|
||||||
globalTimer = 0;
|
globalTimer = 0;
|
||||||
idledCycles = 0;
|
idledCycles = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
ClearPendingEvents();
|
ClearPendingEvents();
|
||||||
UnregisterAllEvents();
|
UnregisterAllEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
externalEventSection.Enter();
|
externalEventSection.Enter();
|
||||||
p.Do(downcount);
|
p.Do(downcount);
|
||||||
p.Do(slicelength);
|
p.Do(slicelength);
|
||||||
p.Do(globalTimer);
|
p.Do(globalTimer);
|
||||||
p.Do(idledCycles);
|
p.Do(idledCycles);
|
||||||
// OK, here we're gonna need to specialize depending on the mode.
|
// OK, here we're gonna need to specialize depending on the mode.
|
||||||
// Should do something generic to serialize linked lists.
|
// Should do something generic to serialize linked lists.
|
||||||
switch (p.GetMode()) {
|
switch (p.GetMode()) {
|
||||||
case PointerWrap::MODE_READ:
|
case PointerWrap::MODE_READ:
|
||||||
{
|
{
|
||||||
ClearPendingEvents();
|
ClearPendingEvents();
|
||||||
if (first)
|
if (first)
|
||||||
PanicAlert("Clear failed.");
|
PanicAlert("Clear failed.");
|
||||||
int more_events = 0;
|
int more_events = 0;
|
||||||
Event *prev = 0;
|
Event *prev = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
p.Do(more_events);
|
p.Do(more_events);
|
||||||
if (!more_events)
|
if (!more_events)
|
||||||
break;
|
break;
|
||||||
Event *ev = new Event;
|
Event *ev = new Event;
|
||||||
if (!prev)
|
if (!prev)
|
||||||
first = ev;
|
first = ev;
|
||||||
else
|
else
|
||||||
prev->next = ev;
|
prev->next = ev;
|
||||||
p.Do(ev->time);
|
p.Do(ev->time);
|
||||||
p.Do(ev->type);
|
p.Do(ev->type);
|
||||||
p.Do(ev->userdata);
|
p.Do(ev->userdata);
|
||||||
ev->next = 0;
|
ev->next = 0;
|
||||||
prev = ev;
|
prev = ev;
|
||||||
ev = ev->next;
|
ev = ev->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PointerWrap::MODE_MEASURE:
|
case PointerWrap::MODE_MEASURE:
|
||||||
case PointerWrap::MODE_WRITE:
|
case PointerWrap::MODE_WRITE:
|
||||||
{
|
{
|
||||||
Event *ev = first;
|
Event *ev = first;
|
||||||
int more_events = 1;
|
int more_events = 1;
|
||||||
while (ev) {
|
while (ev) {
|
||||||
p.Do(more_events);
|
p.Do(more_events);
|
||||||
p.Do(ev->time);
|
p.Do(ev->time);
|
||||||
p.Do(ev->type);
|
p.Do(ev->type);
|
||||||
p.Do(ev->userdata);
|
p.Do(ev->userdata);
|
||||||
ev = ev->next;
|
ev = ev->next;
|
||||||
}
|
}
|
||||||
more_events = 0;
|
more_events = 0;
|
||||||
p.Do(more_events);
|
p.Do(more_events);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
externalEventSection.Leave();
|
externalEventSection.Leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetTicks()
|
u64 GetTicks()
|
||||||
{
|
{
|
||||||
return (u64)globalTimer;
|
return (u64)globalTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetIdleTicks()
|
u64 GetIdleTicks()
|
||||||
{
|
{
|
||||||
return (u64)idledCycles;
|
return (u64)idledCycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is to be called when outside threads, such as the graphics thread, wants to
|
// This is to be called when outside threads, such as the graphics thread, wants to
|
||||||
// schedule things to be executed on the main thread.
|
// schedule things to be executed on the main thread.
|
||||||
void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata)
|
void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata)
|
||||||
{
|
{
|
||||||
externalEventSection.Enter();
|
externalEventSection.Enter();
|
||||||
Event *ne = new Event;
|
Event *ne = new Event;
|
||||||
ne->time = globalTimer + cyclesIntoFuture;
|
ne->time = globalTimer + cyclesIntoFuture;
|
||||||
ne->type = event_type;
|
ne->type = event_type;
|
||||||
ne->next = tsFirst;
|
ne->next = tsFirst;
|
||||||
ne->userdata = userdata;
|
ne->userdata = userdata;
|
||||||
tsFirst = ne;
|
tsFirst = ne;
|
||||||
externalEventSection.Leave();
|
externalEventSection.Leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearPendingEvents()
|
void ClearPendingEvents()
|
||||||
{
|
{
|
||||||
while (first)
|
while (first)
|
||||||
{
|
{
|
||||||
Event *e = first->next;
|
Event *e = first->next;
|
||||||
delete first;
|
delete first;
|
||||||
first = e;
|
first = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddEventToQueue(Event *ne)
|
void AddEventToQueue(Event *ne)
|
||||||
{
|
{
|
||||||
// Damn, this logic got complicated. Must be an easier way.
|
// Damn, this logic got complicated. Must be an easier way.
|
||||||
if (!first)
|
if (!first)
|
||||||
{
|
{
|
||||||
first = ne;
|
first = ne;
|
||||||
ne->next = 0;
|
ne->next = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Event *ptr = first;
|
Event *ptr = first;
|
||||||
Event *prev = 0;
|
Event *prev = 0;
|
||||||
if (ptr->time > ne->time)
|
if (ptr->time > ne->time)
|
||||||
{
|
{
|
||||||
ne->next = first;
|
ne->next = first;
|
||||||
first = ne;
|
first = ne;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
prev = first;
|
prev = first;
|
||||||
ptr = first->next;
|
ptr = first->next;
|
||||||
|
|
||||||
while (ptr)
|
while (ptr)
|
||||||
{
|
{
|
||||||
if (ptr->time <= ne->time)
|
if (ptr->time <= ne->time)
|
||||||
{
|
{
|
||||||
prev = ptr;
|
prev = ptr;
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//OK, ptr points to the item AFTER our new item. Let's insert
|
//OK, ptr points to the item AFTER our new item. Let's insert
|
||||||
ne->next = prev->next;
|
ne->next = prev->next;
|
||||||
prev->next = ne;
|
prev->next = ne;
|
||||||
// Done!
|
// Done!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This must be run ONLY from within the cpu thread
|
// This must be run ONLY from within the cpu thread
|
||||||
// cyclesIntoFuture may be VERY inaccurate if called from anything else
|
// cyclesIntoFuture may be VERY inaccurate if called from anything else
|
||||||
// than Advance
|
// than Advance
|
||||||
void ScheduleEvent(int cyclesIntoFuture, int event_type, u64 userdata)
|
void ScheduleEvent(int cyclesIntoFuture, int event_type, u64 userdata)
|
||||||
{
|
{
|
||||||
Event *ne = new Event;
|
Event *ne = new Event;
|
||||||
ne->userdata = userdata;
|
ne->userdata = userdata;
|
||||||
ne->type = event_type;
|
ne->type = event_type;
|
||||||
ne->time = globalTimer + cyclesIntoFuture;
|
ne->time = globalTimer + cyclesIntoFuture;
|
||||||
|
|
||||||
AddEventToQueue(ne);
|
AddEventToQueue(ne);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted))
|
void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted))
|
||||||
{
|
{
|
||||||
advanceCallback = callback;
|
advanceCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsScheduled(int event_type)
|
bool IsScheduled(int event_type)
|
||||||
{
|
{
|
||||||
if (!first)
|
if (!first)
|
||||||
return false;
|
return false;
|
||||||
Event *e = first;
|
Event *e = first;
|
||||||
while (e) {
|
while (e) {
|
||||||
if (e->type == event_type)
|
if (e->type == event_type)
|
||||||
return true;
|
return true;
|
||||||
e = e->next;
|
e = e->next;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveEvent(int event_type)
|
void RemoveEvent(int event_type)
|
||||||
{
|
{
|
||||||
if (!first)
|
if (!first)
|
||||||
return;
|
return;
|
||||||
if (first->type == event_type)
|
if (first->type == event_type)
|
||||||
{
|
{
|
||||||
Event *next = first->next;
|
Event *next = first->next;
|
||||||
delete first;
|
delete first;
|
||||||
first = next;
|
first = next;
|
||||||
}
|
}
|
||||||
if (!first)
|
if (!first)
|
||||||
return;
|
return;
|
||||||
Event *prev = first;
|
Event *prev = first;
|
||||||
Event *ptr = prev->next;
|
Event *ptr = prev->next;
|
||||||
while (ptr)
|
while (ptr)
|
||||||
{
|
{
|
||||||
if (ptr->type == event_type)
|
if (ptr->type == event_type)
|
||||||
{
|
{
|
||||||
prev->next = ptr->next;
|
prev->next = ptr->next;
|
||||||
delete ptr;
|
delete ptr;
|
||||||
ptr = prev->next;
|
ptr = prev->next;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
prev = ptr;
|
prev = ptr;
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetMaximumSlice(int maximumSliceLength)
|
void SetMaximumSlice(int maximumSliceLength)
|
||||||
{
|
{
|
||||||
maxSliceLength = maximumSliceLength;
|
maxSliceLength = maximumSliceLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Advance()
|
void Advance()
|
||||||
{
|
{
|
||||||
// Move events from async queue into main queue
|
// Move events from async queue into main queue
|
||||||
externalEventSection.Enter();
|
externalEventSection.Enter();
|
||||||
while (tsFirst)
|
while (tsFirst)
|
||||||
{
|
{
|
||||||
Event *next = tsFirst->next;
|
Event *next = tsFirst->next;
|
||||||
AddEventToQueue(tsFirst);
|
AddEventToQueue(tsFirst);
|
||||||
tsFirst = next;
|
tsFirst = next;
|
||||||
}
|
}
|
||||||
externalEventSection.Leave();
|
externalEventSection.Leave();
|
||||||
|
|
||||||
int cyclesExecuted = slicelength - downcount;
|
int cyclesExecuted = slicelength - downcount;
|
||||||
|
|
||||||
globalTimer += cyclesExecuted;
|
globalTimer += cyclesExecuted;
|
||||||
|
|
||||||
while (first)
|
while (first)
|
||||||
{
|
{
|
||||||
if (first->time <= globalTimer)
|
if (first->time <= globalTimer)
|
||||||
{
|
{
|
||||||
// LOG(GEKKO, "[Scheduler] %s (%lld, %lld) ",
|
// LOG(GEKKO, "[Scheduler] %s (%lld, %lld) ",
|
||||||
// first->name ? first->name : "?", (u64)globalTimer, (u64)first->time);
|
// first->name ? first->name : "?", (u64)globalTimer, (u64)first->time);
|
||||||
event_types[first->type].callback(first->userdata, (int)(globalTimer - first->time));
|
event_types[first->type].callback(first->userdata, (int)(globalTimer - first->time));
|
||||||
Event *next = first->next;
|
Event *next = first->next;
|
||||||
delete first;
|
delete first;
|
||||||
first = next;
|
first = next;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!first)
|
if (!first)
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "WARNING - no events in queue. Setting downcount to 10000");
|
LOG(GEKKO, "WARNING - no events in queue. Setting downcount to 10000");
|
||||||
downcount += 10000;
|
downcount += 10000;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
slicelength = (int)(first->time - globalTimer);
|
slicelength = (int)(first->time - globalTimer);
|
||||||
if (slicelength > maxSliceLength)
|
if (slicelength > maxSliceLength)
|
||||||
slicelength = maxSliceLength;
|
slicelength = maxSliceLength;
|
||||||
downcount = slicelength;
|
downcount = slicelength;
|
||||||
}
|
}
|
||||||
if (advanceCallback)
|
if (advanceCallback)
|
||||||
advanceCallback(cyclesExecuted);
|
advanceCallback(cyclesExecuted);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogPendingEvents()
|
void LogPendingEvents()
|
||||||
{
|
{
|
||||||
Event *ptr = first;
|
Event *ptr = first;
|
||||||
while (ptr)
|
while (ptr)
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, ptr->time, ptr->type);
|
LOG(GEKKO, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, ptr->time, ptr->type);
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Idle()
|
void Idle()
|
||||||
{
|
{
|
||||||
LOGV(GEKKO, 3, "Idle");
|
LOGV(GEKKO, 3, "Idle");
|
||||||
|
|
||||||
idledCycles += downcount;
|
idledCycles += downcount;
|
||||||
downcount = 0;
|
downcount = 0;
|
||||||
|
|
||||||
Advance();
|
Advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetScheduledEventsSummary()
|
std::string GetScheduledEventsSummary()
|
||||||
{
|
{
|
||||||
Event *ptr = first;
|
Event *ptr = first;
|
||||||
std::string text = "Scheduled events\n";
|
std::string text = "Scheduled events\n";
|
||||||
text.reserve(1000);
|
text.reserve(1000);
|
||||||
while (ptr)
|
while (ptr)
|
||||||
{
|
{
|
||||||
unsigned int t = ptr->type;
|
unsigned int t = ptr->type;
|
||||||
if (t < 0 || t >= event_types.size())
|
if (t < 0 || t >= event_types.size())
|
||||||
PanicAlert("Invalid event type %i", t);
|
PanicAlert("Invalid event type %i", t);
|
||||||
const char *name = event_types[ptr->type].name;
|
const char *name = event_types[ptr->type].name;
|
||||||
if (!name)
|
if (!name)
|
||||||
name = "[unknown]";
|
name = "[unknown]";
|
||||||
text += StringFromFormat("%s : %i %08x%08x\n", event_types[ptr->type].name, ptr->time, ptr->userdata >> 32, ptr->userdata);
|
text += StringFromFormat("%s : %i %08x%08x\n", event_types[ptr->type].name, ptr->time, ptr->userdata >> 32, ptr->userdata);
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,195 +1,195 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
// Lame slow breakpoint system
|
// Lame slow breakpoint system
|
||||||
// TODO: a real one
|
// TODO: a real one
|
||||||
|
|
||||||
//
|
//
|
||||||
// [F|RES]: this class isn't really nice... for a better management we should use a base class for
|
// [F|RES]: this class isn't really nice... for a better management we should use a base class for
|
||||||
// breakpoints and memory checks. but probably this will be slower too
|
// breakpoints and memory checks. but probably this will be slower too
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "../HW/CPU.h"
|
#include "../HW/CPU.h"
|
||||||
#include "../Host.h"
|
#include "../Host.h"
|
||||||
#include "../PowerPC/SymbolDB.h"
|
#include "../PowerPC/SymbolDB.h"
|
||||||
#include "Debugger_BreakPoints.h"
|
#include "Debugger_BreakPoints.h"
|
||||||
|
|
||||||
CBreakPoints::TBreakPoints CBreakPoints::m_BreakPoints;
|
CBreakPoints::TBreakPoints CBreakPoints::m_BreakPoints;
|
||||||
CBreakPoints::TMemChecks CBreakPoints::m_MemChecks;
|
CBreakPoints::TMemChecks CBreakPoints::m_MemChecks;
|
||||||
u32 CBreakPoints::m_iBreakOnCount = 0;
|
u32 CBreakPoints::m_iBreakOnCount = 0;
|
||||||
|
|
||||||
TMemCheck::TMemCheck()
|
TMemCheck::TMemCheck()
|
||||||
{
|
{
|
||||||
numHits = 0;
|
numHits = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TMemCheck::Action(u32 iValue, u32 addr, bool write, int size, u32 pc)
|
void TMemCheck::Action(u32 iValue, u32 addr, bool write, int size, u32 pc)
|
||||||
{
|
{
|
||||||
if ((write && OnWrite) || (!write && OnRead))
|
if ((write && OnWrite) || (!write && OnRead))
|
||||||
{
|
{
|
||||||
if (Log)
|
if (Log)
|
||||||
{
|
{
|
||||||
LOG(MEMMAP,"CHK %08x %s%i at %08x (%s)",
|
LOG(MEMMAP,"CHK %08x %s%i at %08x (%s)",
|
||||||
iValue, write ? "Write" : "Read", // read or write
|
iValue, write ? "Write" : "Read", // read or write
|
||||||
size*8, addr, // address
|
size*8, addr, // address
|
||||||
g_symbolDB.GetDescription(addr) // symbol map description
|
g_symbolDB.GetDescription(addr) // symbol map description
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (Break)
|
if (Break)
|
||||||
CCPU::Break();
|
CCPU::Break();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBreakPoints::IsAddressBreakPoint(u32 _iAddress)
|
bool CBreakPoints::IsAddressBreakPoint(u32 _iAddress)
|
||||||
{
|
{
|
||||||
std::vector<TBreakPoint>::iterator iter;
|
std::vector<TBreakPoint>::iterator iter;
|
||||||
|
|
||||||
for (iter = m_BreakPoints.begin(); iter != m_BreakPoints.end(); ++iter)
|
for (iter = m_BreakPoints.begin(); iter != m_BreakPoints.end(); ++iter)
|
||||||
if ((*iter).iAddress == _iAddress)
|
if ((*iter).iAddress == _iAddress)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBreakPoints::IsTempBreakPoint(u32 _iAddress)
|
bool CBreakPoints::IsTempBreakPoint(u32 _iAddress)
|
||||||
{
|
{
|
||||||
std::vector<TBreakPoint>::iterator iter;
|
std::vector<TBreakPoint>::iterator iter;
|
||||||
|
|
||||||
for (iter = m_BreakPoints.begin(); iter != m_BreakPoints.end(); ++iter)
|
for (iter = m_BreakPoints.begin(); iter != m_BreakPoints.end(); ++iter)
|
||||||
if ((*iter).iAddress == _iAddress && (*iter).bTemporary)
|
if ((*iter).iAddress == _iAddress && (*iter).bTemporary)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TMemCheck *CBreakPoints::GetMemCheck(u32 address)
|
TMemCheck *CBreakPoints::GetMemCheck(u32 address)
|
||||||
{
|
{
|
||||||
std::vector<TMemCheck>::iterator iter;
|
std::vector<TMemCheck>::iterator iter;
|
||||||
for (iter = m_MemChecks.begin(); iter != m_MemChecks.end(); ++iter)
|
for (iter = m_MemChecks.begin(); iter != m_MemChecks.end(); ++iter)
|
||||||
{
|
{
|
||||||
if ((*iter).bRange)
|
if ((*iter).bRange)
|
||||||
{
|
{
|
||||||
if (address >= (*iter).StartAddress && address <= (*iter).EndAddress)
|
if (address >= (*iter).StartAddress && address <= (*iter).EndAddress)
|
||||||
return &(*iter);
|
return &(*iter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((*iter).StartAddress==address)
|
if ((*iter).StartAddress==address)
|
||||||
return &(*iter);
|
return &(*iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//none found
|
//none found
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBreakPoints::AddBreakPoint(u32 _iAddress, bool temp)
|
void CBreakPoints::AddBreakPoint(u32 _iAddress, bool temp)
|
||||||
{
|
{
|
||||||
if (!IsAddressBreakPoint(_iAddress)) // only add new addresses
|
if (!IsAddressBreakPoint(_iAddress)) // only add new addresses
|
||||||
{
|
{
|
||||||
TBreakPoint pt; // breakpoint settings
|
TBreakPoint pt; // breakpoint settings
|
||||||
pt.bOn = true;
|
pt.bOn = true;
|
||||||
pt.bTemporary = temp;
|
pt.bTemporary = temp;
|
||||||
pt.iAddress = _iAddress;
|
pt.iAddress = _iAddress;
|
||||||
|
|
||||||
m_BreakPoints.push_back(pt);
|
m_BreakPoints.push_back(pt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBreakPoints::RemoveBreakPoint(u32 _iAddress)
|
void CBreakPoints::RemoveBreakPoint(u32 _iAddress)
|
||||||
{
|
{
|
||||||
std::vector<TBreakPoint>::iterator iter;
|
std::vector<TBreakPoint>::iterator iter;
|
||||||
|
|
||||||
for (iter = m_BreakPoints.begin(); iter != m_BreakPoints.end(); ++iter)
|
for (iter = m_BreakPoints.begin(); iter != m_BreakPoints.end(); ++iter)
|
||||||
{
|
{
|
||||||
if ((*iter).iAddress == _iAddress)
|
if ((*iter).iAddress == _iAddress)
|
||||||
{
|
{
|
||||||
m_BreakPoints.erase(iter);
|
m_BreakPoints.erase(iter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Host_UpdateBreakPointView();
|
Host_UpdateBreakPointView();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBreakPoints::ClearAllBreakPoints()
|
void CBreakPoints::ClearAllBreakPoints()
|
||||||
{
|
{
|
||||||
m_BreakPoints.clear();
|
m_BreakPoints.clear();
|
||||||
m_MemChecks.clear();
|
m_MemChecks.clear();
|
||||||
Host_UpdateBreakPointView();
|
Host_UpdateBreakPointView();
|
||||||
}
|
}
|
||||||
|
|
||||||
// update breakpoint window
|
// update breakpoint window
|
||||||
void CBreakPoints::UpdateBreakPointView()
|
void CBreakPoints::UpdateBreakPointView()
|
||||||
{
|
{
|
||||||
Host_UpdateBreakPointView();
|
Host_UpdateBreakPointView();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBreakPoints::AddMemoryCheck(const TMemCheck& _rMemoryCheck)
|
void CBreakPoints::AddMemoryCheck(const TMemCheck& _rMemoryCheck)
|
||||||
{
|
{
|
||||||
m_MemChecks.push_back(_rMemoryCheck);
|
m_MemChecks.push_back(_rMemoryCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBreakPoints::AddAutoBreakpoints()
|
void CBreakPoints::AddAutoBreakpoints()
|
||||||
{
|
{
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||||
#if 1
|
#if 1
|
||||||
const char *bps[] = {
|
const char *bps[] = {
|
||||||
"PPCHalt",
|
"PPCHalt",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(bps) / sizeof(const char *); i++)
|
for (int i = 0; i < sizeof(bps) / sizeof(const char *); i++)
|
||||||
{
|
{
|
||||||
Symbol *symbol = g_symbolDB.GetSymbolFromName(bps[i]);
|
Symbol *symbol = g_symbolDB.GetSymbolFromName(bps[i]);
|
||||||
if (symbol)
|
if (symbol)
|
||||||
AddBreakPoint(symbol->address, false);
|
AddBreakPoint(symbol->address, false);
|
||||||
}
|
}
|
||||||
Host_UpdateBreakPointView();
|
Host_UpdateBreakPointView();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBreakPoints::DeleteElementByAddress(u32 _Address)
|
void CBreakPoints::DeleteElementByAddress(u32 _Address)
|
||||||
{
|
{
|
||||||
// first check breakpoints
|
// first check breakpoints
|
||||||
{
|
{
|
||||||
std::vector<TBreakPoint>::iterator iter;
|
std::vector<TBreakPoint>::iterator iter;
|
||||||
for (iter = m_BreakPoints.begin(); iter != m_BreakPoints.end(); ++iter)
|
for (iter = m_BreakPoints.begin(); iter != m_BreakPoints.end(); ++iter)
|
||||||
{
|
{
|
||||||
if ((*iter).iAddress == _Address)
|
if ((*iter).iAddress == _Address)
|
||||||
{
|
{
|
||||||
m_BreakPoints.erase(iter);
|
m_BreakPoints.erase(iter);
|
||||||
Host_UpdateBreakPointView();
|
Host_UpdateBreakPointView();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// second memory check checkpoint
|
// second memory check checkpoint
|
||||||
std::vector<TMemCheck>::iterator iter;
|
std::vector<TMemCheck>::iterator iter;
|
||||||
for (iter = m_MemChecks.begin(); iter != m_MemChecks.end(); ++iter)
|
for (iter = m_MemChecks.begin(); iter != m_MemChecks.end(); ++iter)
|
||||||
{
|
{
|
||||||
if ((*iter).StartAddress == _Address)
|
if ((*iter).StartAddress == _Address)
|
||||||
{
|
{
|
||||||
m_MemChecks.erase(iter);
|
m_MemChecks.erase(iter);
|
||||||
Host_UpdateBreakPointView();
|
Host_UpdateBreakPointView();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,157 +1,157 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "Debugger_SymbolMap.h"
|
#include "Debugger_SymbolMap.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "../PowerPC/PPCAnalyst.h"
|
#include "../PowerPC/PPCAnalyst.h"
|
||||||
#include "../PowerPC/SymbolDB.h"
|
#include "../PowerPC/SymbolDB.h"
|
||||||
#include "../../../../Externals/Bochs_disasm/PowerPCDisasm.h"
|
#include "../../../../Externals/Bochs_disasm/PowerPCDisasm.h"
|
||||||
|
|
||||||
namespace Debugger
|
namespace Debugger
|
||||||
{
|
{
|
||||||
|
|
||||||
bool GetCallstack(std::vector<CallstackEntry> &output)
|
bool GetCallstack(std::vector<CallstackEntry> &output)
|
||||||
{
|
{
|
||||||
if (Core::GetState() == Core::CORE_UNINITIALIZED)
|
if (Core::GetState() == Core::CORE_UNINITIALIZED)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!Memory::IsRAMAddress(PowerPC::ppcState.gpr[1]))
|
if (!Memory::IsRAMAddress(PowerPC::ppcState.gpr[1]))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
u32 addr = Memory::ReadUnchecked_U32(PowerPC::ppcState.gpr[1]); // SP
|
u32 addr = Memory::ReadUnchecked_U32(PowerPC::ppcState.gpr[1]); // SP
|
||||||
if (LR == 0) {
|
if (LR == 0) {
|
||||||
CallstackEntry entry;
|
CallstackEntry entry;
|
||||||
entry.Name = "(error: LR=0)";
|
entry.Name = "(error: LR=0)";
|
||||||
entry.vAddress = 0x0;
|
entry.vAddress = 0x0;
|
||||||
output.push_back(entry);
|
output.push_back(entry);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int count = 1;
|
int count = 1;
|
||||||
if (g_symbolDB.GetDescription(PowerPC::ppcState.pc) != g_symbolDB.GetDescription(LR))
|
if (g_symbolDB.GetDescription(PowerPC::ppcState.pc) != g_symbolDB.GetDescription(LR))
|
||||||
{
|
{
|
||||||
CallstackEntry entry;
|
CallstackEntry entry;
|
||||||
entry.Name = StringFromFormat(" * %s [ LR = %08x ]\n", g_symbolDB.GetDescription(LR), LR);
|
entry.Name = StringFromFormat(" * %s [ LR = %08x ]\n", g_symbolDB.GetDescription(LR), LR);
|
||||||
entry.vAddress = 0x0;
|
entry.vAddress = 0x0;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//walk the stack chain
|
//walk the stack chain
|
||||||
while ((addr != 0xFFFFFFFF) && (addr != 0) && (count++ < 20) && (PowerPC::ppcState.gpr[1] != 0))
|
while ((addr != 0xFFFFFFFF) && (addr != 0) && (count++ < 20) && (PowerPC::ppcState.gpr[1] != 0))
|
||||||
{
|
{
|
||||||
if (!Memory::IsRAMAddress(addr + 4))
|
if (!Memory::IsRAMAddress(addr + 4))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
u32 func = Memory::ReadUnchecked_U32(addr + 4);
|
u32 func = Memory::ReadUnchecked_U32(addr + 4);
|
||||||
const char *str = g_symbolDB.GetDescription(func);
|
const char *str = g_symbolDB.GetDescription(func);
|
||||||
if (!str || strlen(str) == 0 || !strcmp(str, "Invalid"))
|
if (!str || strlen(str) == 0 || !strcmp(str, "Invalid"))
|
||||||
str = "(unknown)";
|
str = "(unknown)";
|
||||||
|
|
||||||
CallstackEntry entry;
|
CallstackEntry entry;
|
||||||
entry.Name = StringFromFormat(" * %s [ addr = %08x ]\n", str, func);
|
entry.Name = StringFromFormat(" * %s [ addr = %08x ]\n", str, func);
|
||||||
entry.vAddress = func;
|
entry.vAddress = func;
|
||||||
output.push_back(entry);
|
output.push_back(entry);
|
||||||
|
|
||||||
if (!Memory::IsRAMAddress(addr))
|
if (!Memory::IsRAMAddress(addr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
addr = Memory::ReadUnchecked_U32(addr);
|
addr = Memory::ReadUnchecked_U32(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintCallstack()
|
void PrintCallstack()
|
||||||
{
|
{
|
||||||
u32 addr = Memory::ReadUnchecked_U32(PowerPC::ppcState.gpr[1]); // SP
|
u32 addr = Memory::ReadUnchecked_U32(PowerPC::ppcState.gpr[1]); // SP
|
||||||
|
|
||||||
printf("\n == STACK TRACE - SP = %08x ==\n", PowerPC::ppcState.gpr[1]);
|
printf("\n == STACK TRACE - SP = %08x ==\n", PowerPC::ppcState.gpr[1]);
|
||||||
|
|
||||||
if (LR == 0) {
|
if (LR == 0) {
|
||||||
printf(" LR = 0 - this is bad\n");
|
printf(" LR = 0 - this is bad\n");
|
||||||
}
|
}
|
||||||
int count = 1;
|
int count = 1;
|
||||||
if (g_symbolDB.GetDescription(PowerPC::ppcState.pc) != g_symbolDB.GetDescription(LR))
|
if (g_symbolDB.GetDescription(PowerPC::ppcState.pc) != g_symbolDB.GetDescription(LR))
|
||||||
{
|
{
|
||||||
printf(" * %s [ LR = %08x ]\n", g_symbolDB.GetDescription(LR), LR);
|
printf(" * %s [ LR = %08x ]\n", g_symbolDB.GetDescription(LR), LR);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//walk the stack chain
|
//walk the stack chain
|
||||||
while ((addr != 0xFFFFFFFF) && (addr != 0) && (count++ < 20) && (PowerPC::ppcState.gpr[1] != 0))
|
while ((addr != 0xFFFFFFFF) && (addr != 0) && (count++ < 20) && (PowerPC::ppcState.gpr[1] != 0))
|
||||||
{
|
{
|
||||||
u32 func = Memory::ReadUnchecked_U32(addr + 4);
|
u32 func = Memory::ReadUnchecked_U32(addr + 4);
|
||||||
const char *str = g_symbolDB.GetDescription(func);
|
const char *str = g_symbolDB.GetDescription(func);
|
||||||
if (!str || strlen(str) == 0 || !strcmp(str, "Invalid"))
|
if (!str || strlen(str) == 0 || !strcmp(str, "Invalid"))
|
||||||
str = "(unknown)";
|
str = "(unknown)";
|
||||||
printf( " * %s [ addr = %08x ]\n", str, func);
|
printf( " * %s [ addr = %08x ]\n", str, func);
|
||||||
addr = Memory::ReadUnchecked_U32(addr);
|
addr = Memory::ReadUnchecked_U32(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintCallstack(LogTypes::LOG_TYPE _Log)
|
void PrintCallstack(LogTypes::LOG_TYPE _Log)
|
||||||
{
|
{
|
||||||
u32 addr = Memory::ReadUnchecked_U32(PowerPC::ppcState.gpr[1]); // SP
|
u32 addr = Memory::ReadUnchecked_U32(PowerPC::ppcState.gpr[1]); // SP
|
||||||
|
|
||||||
__Logv(_Log, 1, "\n == STACK TRACE - SP = %08x ==\n", PowerPC::ppcState.gpr[1]);
|
__Logv(_Log, 1, "\n == STACK TRACE - SP = %08x ==\n", PowerPC::ppcState.gpr[1]);
|
||||||
|
|
||||||
if (LR == 0) {
|
if (LR == 0) {
|
||||||
__Logv(_Log, 1, " LR = 0 - this is bad\n");
|
__Logv(_Log, 1, " LR = 0 - this is bad\n");
|
||||||
}
|
}
|
||||||
int count = 1;
|
int count = 1;
|
||||||
if (g_symbolDB.GetDescription(PowerPC::ppcState.pc) != g_symbolDB.GetDescription(LR))
|
if (g_symbolDB.GetDescription(PowerPC::ppcState.pc) != g_symbolDB.GetDescription(LR))
|
||||||
{
|
{
|
||||||
__Log(_Log, " * %s [ LR = %08x ]\n", g_symbolDB.GetDescription(LR), LR);
|
__Log(_Log, " * %s [ LR = %08x ]\n", g_symbolDB.GetDescription(LR), LR);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//walk the stack chain
|
//walk the stack chain
|
||||||
while ((addr != 0xFFFFFFFF) && (addr != 0) && (count++ < 20) && (PowerPC::ppcState.gpr[1] != 0))
|
while ((addr != 0xFFFFFFFF) && (addr != 0) && (count++ < 20) && (PowerPC::ppcState.gpr[1] != 0))
|
||||||
{
|
{
|
||||||
u32 func = Memory::ReadUnchecked_U32(addr + 4);
|
u32 func = Memory::ReadUnchecked_U32(addr + 4);
|
||||||
const char *str = g_symbolDB.GetDescription(func);
|
const char *str = g_symbolDB.GetDescription(func);
|
||||||
if (!str || strlen(str) == 0 || !strcmp(str, "Invalid"))
|
if (!str || strlen(str) == 0 || !strcmp(str, "Invalid"))
|
||||||
str = "(unknown)";
|
str = "(unknown)";
|
||||||
__Logv(_Log, 3, " * %s [ addr = %08x ]\n", str, func);
|
__Logv(_Log, 3, " * %s [ addr = %08x ]\n", str, func);
|
||||||
addr = Memory::ReadUnchecked_U32(addr);
|
addr = Memory::ReadUnchecked_U32(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintDataBuffer(LogTypes::LOG_TYPE _Log, u8* _pData, size_t _Size, const char* _title)
|
void PrintDataBuffer(LogTypes::LOG_TYPE _Log, u8* _pData, size_t _Size, const char* _title)
|
||||||
{
|
{
|
||||||
__Log(_Log, _title);
|
__Log(_Log, _title);
|
||||||
for (u32 j=0; j<_Size;)
|
for (u32 j=0; j<_Size;)
|
||||||
{
|
{
|
||||||
std::string Temp;
|
std::string Temp;
|
||||||
for (int i=0; i<16; i++)
|
for (int i=0; i<16; i++)
|
||||||
{
|
{
|
||||||
char Buffer[128];
|
char Buffer[128];
|
||||||
sprintf(Buffer, "%02x ", _pData[j++]);
|
sprintf(Buffer, "%02x ", _pData[j++]);
|
||||||
Temp.append(Buffer);
|
Temp.append(Buffer);
|
||||||
|
|
||||||
if (j >= _Size)
|
if (j >= _Size)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
__Log(_Log, " Data: %s", Temp.c_str());
|
__Log(_Log, " Data: %s", Temp.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace Debugger
|
} // end of namespace Debugger
|
||||||
|
|
|
@ -1,87 +1,87 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Dump.h"
|
#include "Dump.h"
|
||||||
|
|
||||||
CDump::CDump(const char* _szFilename) :
|
CDump::CDump(const char* _szFilename) :
|
||||||
m_pData(NULL),
|
m_pData(NULL),
|
||||||
m_bInit(false)
|
m_bInit(false)
|
||||||
{
|
{
|
||||||
FILE* pStream = fopen(_szFilename, "rb");
|
FILE* pStream = fopen(_szFilename, "rb");
|
||||||
if (pStream != NULL)
|
if (pStream != NULL)
|
||||||
{
|
{
|
||||||
fseek(pStream, 0, SEEK_END);
|
fseek(pStream, 0, SEEK_END);
|
||||||
m_size = ftell(pStream);
|
m_size = ftell(pStream);
|
||||||
fseek(pStream, 0, SEEK_SET);
|
fseek(pStream, 0, SEEK_SET);
|
||||||
|
|
||||||
m_pData = new u8[m_size];
|
m_pData = new u8[m_size];
|
||||||
|
|
||||||
fread(m_pData, m_size, 1, pStream);
|
fread(m_pData, m_size, 1, pStream);
|
||||||
|
|
||||||
fclose(pStream);
|
fclose(pStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CDump::~CDump(void)
|
CDump::~CDump(void)
|
||||||
{
|
{
|
||||||
if (m_pData != NULL)
|
if (m_pData != NULL)
|
||||||
{
|
{
|
||||||
delete [] m_pData;
|
delete [] m_pData;
|
||||||
m_pData = NULL;
|
m_pData = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
CDump::GetNumberOfSteps(void)
|
CDump::GetNumberOfSteps(void)
|
||||||
{
|
{
|
||||||
return (int)(m_size / STRUCTUR_SIZE);
|
return (int)(m_size / STRUCTUR_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32
|
u32
|
||||||
CDump::GetGPR(int _step, int _gpr)
|
CDump::GetGPR(int _step, int _gpr)
|
||||||
{
|
{
|
||||||
u32 offset = _step * STRUCTUR_SIZE;
|
u32 offset = _step * STRUCTUR_SIZE;
|
||||||
|
|
||||||
if (offset >= m_size)
|
if (offset >= m_size)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return Read32(offset + OFFSET_GPR + (_gpr * 4));
|
return Read32(offset + OFFSET_GPR + (_gpr * 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
u32
|
u32
|
||||||
CDump::GetPC(int _step)
|
CDump::GetPC(int _step)
|
||||||
{
|
{
|
||||||
u32 offset = _step * STRUCTUR_SIZE;
|
u32 offset = _step * STRUCTUR_SIZE;
|
||||||
|
|
||||||
if (offset >= m_size)
|
if (offset >= m_size)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return Read32(offset + OFFSET_PC);
|
return Read32(offset + OFFSET_PC);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32
|
u32
|
||||||
CDump::Read32(u32 _pos)
|
CDump::Read32(u32 _pos)
|
||||||
{
|
{
|
||||||
u32 result = (m_pData[_pos+0] << 24) |
|
u32 result = (m_pData[_pos+0] << 24) |
|
||||||
(m_pData[_pos+1] << 16) |
|
(m_pData[_pos+1] << 16) |
|
||||||
(m_pData[_pos+2] << 8) |
|
(m_pData[_pos+2] << 8) |
|
||||||
(m_pData[_pos+3] << 0);
|
(m_pData[_pos+3] << 0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,150 +1,150 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Debugger_BreakPoints.h"
|
#include "Debugger_BreakPoints.h"
|
||||||
#include "Debugger_SymbolMap.h"
|
#include "Debugger_SymbolMap.h"
|
||||||
#include "DebugInterface.h"
|
#include "DebugInterface.h"
|
||||||
#include "PPCDebugInterface.h"
|
#include "PPCDebugInterface.h"
|
||||||
#include "PowerPCDisasm.h"
|
#include "PowerPCDisasm.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "../PowerPC/SymbolDB.h"
|
#include "../PowerPC/SymbolDB.h"
|
||||||
|
|
||||||
// Not thread safe.
|
// Not thread safe.
|
||||||
const char *PPCDebugInterface::disasm(unsigned int address)
|
const char *PPCDebugInterface::disasm(unsigned int address)
|
||||||
{
|
{
|
||||||
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
||||||
{
|
{
|
||||||
if (Memory::IsRAMAddress(address))
|
if (Memory::IsRAMAddress(address))
|
||||||
{
|
{
|
||||||
u32 op = Memory::Read_Instruction(address);
|
u32 op = Memory::Read_Instruction(address);
|
||||||
return DisassembleGekko(op, address);
|
return DisassembleGekko(op, address);
|
||||||
}
|
}
|
||||||
return "No RAM here - invalid";
|
return "No RAM here - invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char tmp[] = "<unknown>";
|
static const char tmp[] = "<unknown>";
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *PPCDebugInterface::getRawMemoryString(unsigned int address)
|
const char *PPCDebugInterface::getRawMemoryString(unsigned int address)
|
||||||
{
|
{
|
||||||
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
||||||
{
|
{
|
||||||
if (address < 0xE0000000)
|
if (address < 0xE0000000)
|
||||||
{
|
{
|
||||||
static char str[256] ={0};
|
static char str[256] ={0};
|
||||||
if (sprintf(str,"%08X",readMemory(address))!=8) {
|
if (sprintf(str,"%08X",readMemory(address))!=8) {
|
||||||
PanicAlert("getRawMemoryString -> WTF! ( as read somewhere;) )");
|
PanicAlert("getRawMemoryString -> WTF! ( as read somewhere;) )");
|
||||||
return ":(";
|
return ":(";
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
return "No RAM";
|
return "No RAM";
|
||||||
}
|
}
|
||||||
static const char tmp[] = "<unknown>";
|
static const char tmp[] = "<unknown>";
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int PPCDebugInterface::readMemory(unsigned int address)
|
unsigned int PPCDebugInterface::readMemory(unsigned int address)
|
||||||
{
|
{
|
||||||
return Memory::ReadUnchecked_U32(address);
|
return Memory::ReadUnchecked_U32(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int PPCDebugInterface::readInstruction(unsigned int address)
|
unsigned int PPCDebugInterface::readInstruction(unsigned int address)
|
||||||
{
|
{
|
||||||
return Memory::Read_Instruction(address);
|
return Memory::Read_Instruction(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PPCDebugInterface::isAlive()
|
bool PPCDebugInterface::isAlive()
|
||||||
{
|
{
|
||||||
return Core::GetState() != Core::CORE_UNINITIALIZED;
|
return Core::GetState() != Core::CORE_UNINITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PPCDebugInterface::isBreakpoint(unsigned int address)
|
bool PPCDebugInterface::isBreakpoint(unsigned int address)
|
||||||
{
|
{
|
||||||
return CBreakPoints::IsAddressBreakPoint(address);
|
return CBreakPoints::IsAddressBreakPoint(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::setBreakpoint(unsigned int address)
|
void PPCDebugInterface::setBreakpoint(unsigned int address)
|
||||||
{
|
{
|
||||||
CBreakPoints::AddBreakPoint(address);
|
CBreakPoints::AddBreakPoint(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::clearBreakpoint(unsigned int address)
|
void PPCDebugInterface::clearBreakpoint(unsigned int address)
|
||||||
{
|
{
|
||||||
CBreakPoints::RemoveBreakPoint(address);
|
CBreakPoints::RemoveBreakPoint(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::clearAllBreakpoints() {}
|
void PPCDebugInterface::clearAllBreakpoints() {}
|
||||||
|
|
||||||
void PPCDebugInterface::toggleBreakpoint(unsigned int address)
|
void PPCDebugInterface::toggleBreakpoint(unsigned int address)
|
||||||
{
|
{
|
||||||
CBreakPoints::IsAddressBreakPoint(address) ? CBreakPoints::RemoveBreakPoint(address) : CBreakPoints::AddBreakPoint(address);
|
CBreakPoints::IsAddressBreakPoint(address) ? CBreakPoints::RemoveBreakPoint(address) : CBreakPoints::AddBreakPoint(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::insertBLR(unsigned int address)
|
void PPCDebugInterface::insertBLR(unsigned int address)
|
||||||
{
|
{
|
||||||
Memory::Write_U32(0x4e800020, address);
|
Memory::Write_U32(0x4e800020, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// Separate the blocks with colors.
|
// Separate the blocks with colors.
|
||||||
// -------------
|
// -------------
|
||||||
int PPCDebugInterface::getColor(unsigned int address)
|
int PPCDebugInterface::getColor(unsigned int address)
|
||||||
{
|
{
|
||||||
if (!Memory::IsRAMAddress(address))
|
if (!Memory::IsRAMAddress(address))
|
||||||
return 0xeeeeee;
|
return 0xeeeeee;
|
||||||
int colors[6] =
|
int colors[6] =
|
||||||
{
|
{
|
||||||
0xd0FFFF // light cyan
|
0xd0FFFF // light cyan
|
||||||
,0xFFd0d0 // light red
|
,0xFFd0d0 // light red
|
||||||
,0xd8d8FF // light blue
|
,0xd8d8FF // light blue
|
||||||
,0xFFd0FF // light purple
|
,0xFFd0FF // light purple
|
||||||
,0xd0FFd0 // light green
|
,0xd0FFd0 // light green
|
||||||
,0xFFFFd0 // light yellow
|
,0xFFFFd0 // light yellow
|
||||||
};
|
};
|
||||||
Symbol *symbol = g_symbolDB.GetSymbolFromAddr(address);
|
Symbol *symbol = g_symbolDB.GetSymbolFromAddr(address);
|
||||||
if (!symbol) return 0xFFFFFF;
|
if (!symbol) return 0xFFFFFF;
|
||||||
if (symbol->type != Symbol::SYMBOL_FUNCTION)
|
if (symbol->type != Symbol::SYMBOL_FUNCTION)
|
||||||
return 0xEEEEFF;
|
return 0xEEEEFF;
|
||||||
return colors[symbol->index % 6];
|
return colors[symbol->index % 6];
|
||||||
}
|
}
|
||||||
// =============
|
// =============
|
||||||
|
|
||||||
|
|
||||||
std::string PPCDebugInterface::getDescription(unsigned int address)
|
std::string PPCDebugInterface::getDescription(unsigned int address)
|
||||||
{
|
{
|
||||||
return g_symbolDB.GetDescription(address);
|
return g_symbolDB.GetDescription(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int PPCDebugInterface::getPC()
|
unsigned int PPCDebugInterface::getPC()
|
||||||
{
|
{
|
||||||
return PowerPC::ppcState.pc;
|
return PowerPC::ppcState.pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::setPC(unsigned int address)
|
void PPCDebugInterface::setPC(unsigned int address)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.pc = address;
|
PowerPC::ppcState.pc = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::runToBreakpoint()
|
void PPCDebugInterface::runToBreakpoint()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,141 +1,141 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "HLE.h"
|
#include "HLE.h"
|
||||||
|
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "../PowerPC/SymbolDB.h"
|
#include "../PowerPC/SymbolDB.h"
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
#include "../Debugger/Debugger_SymbolMap.h"
|
#include "../Debugger/Debugger_SymbolMap.h"
|
||||||
#include "../Debugger/Debugger_BreakPoints.h"
|
#include "../Debugger/Debugger_BreakPoints.h"
|
||||||
|
|
||||||
#include "HLE_OS.h"
|
#include "HLE_OS.h"
|
||||||
#include "HLE_Misc.h"
|
#include "HLE_Misc.h"
|
||||||
|
|
||||||
namespace HLE
|
namespace HLE
|
||||||
{
|
{
|
||||||
|
|
||||||
using namespace PowerPC;
|
using namespace PowerPC;
|
||||||
|
|
||||||
typedef void (*TPatchFunction)();
|
typedef void (*TPatchFunction)();
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
HLE_RETURNTYPE_BLR = 0,
|
HLE_RETURNTYPE_BLR = 0,
|
||||||
HLE_RETURNTYPE_RFI = 1,
|
HLE_RETURNTYPE_RFI = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SPatch
|
struct SPatch
|
||||||
{
|
{
|
||||||
char m_szPatchName[128];
|
char m_szPatchName[128];
|
||||||
TPatchFunction PatchFunction;
|
TPatchFunction PatchFunction;
|
||||||
int returnType;
|
int returnType;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const SPatch OSPatches[] =
|
static const SPatch OSPatches[] =
|
||||||
{
|
{
|
||||||
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
|
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
|
||||||
|
|
||||||
// speedup
|
// speedup
|
||||||
{ "OSProtectRange", HLE_Misc::UnimplementedFunctionFalse },
|
{ "OSProtectRange", HLE_Misc::UnimplementedFunctionFalse },
|
||||||
// { "THPPlayerGetState", HLE_Misc:THPPlayerGetState },
|
// { "THPPlayerGetState", HLE_Misc:THPPlayerGetState },
|
||||||
|
|
||||||
|
|
||||||
// debug out is very nice ;)
|
// debug out is very nice ;)
|
||||||
{ "OSReport", HLE_OS::HLE_OSReport },
|
{ "OSReport", HLE_OS::HLE_OSReport },
|
||||||
{ "OSPanic", HLE_OS::HLE_OSPanic },
|
{ "OSPanic", HLE_OS::HLE_OSPanic },
|
||||||
{ "vprintf", HLE_OS::HLE_vprintf },
|
{ "vprintf", HLE_OS::HLE_vprintf },
|
||||||
{ "printf", HLE_OS::HLE_printf },
|
{ "printf", HLE_OS::HLE_printf },
|
||||||
{ "puts", HLE_OS::HLE_printf }, //gcc-optimized printf?
|
{ "puts", HLE_OS::HLE_printf }, //gcc-optimized printf?
|
||||||
|
|
||||||
// wii only
|
// wii only
|
||||||
{ "__OSInitAudioSystem", HLE_Misc::UnimplementedFunction },
|
{ "__OSInitAudioSystem", HLE_Misc::UnimplementedFunction },
|
||||||
|
|
||||||
// Super Monkey Ball
|
// Super Monkey Ball
|
||||||
{ ".evil_vec_cosine", HLE_Misc::SMB_EvilVecCosine },
|
{ ".evil_vec_cosine", HLE_Misc::SMB_EvilVecCosine },
|
||||||
{ ".evil_normalize", HLE_Misc::SMB_EvilNormalize },
|
{ ".evil_normalize", HLE_Misc::SMB_EvilNormalize },
|
||||||
{ ".evil_vec_setlength", HLE_Misc::SMB_evil_vec_setlength },
|
{ ".evil_vec_setlength", HLE_Misc::SMB_evil_vec_setlength },
|
||||||
{ "PanicAlert", HLE_Misc::PanicAlert },
|
{ "PanicAlert", HLE_Misc::PanicAlert },
|
||||||
{ ".sqrt_internal_needs_cr1", HLE_Misc::SMB_sqrt_internal },
|
{ ".sqrt_internal_needs_cr1", HLE_Misc::SMB_sqrt_internal },
|
||||||
{ ".rsqrt_internal_needs_cr1", HLE_Misc::SMB_rsqrt_internal },
|
{ ".rsqrt_internal_needs_cr1", HLE_Misc::SMB_rsqrt_internal },
|
||||||
{ ".atan2", HLE_Misc::SMB_atan2},
|
{ ".atan2", HLE_Misc::SMB_atan2},
|
||||||
|
|
||||||
// special
|
// special
|
||||||
// { "GXPeekZ", HLE_Misc::GXPeekZ},
|
// { "GXPeekZ", HLE_Misc::GXPeekZ},
|
||||||
// { "GXPeekARGB", HLE_Misc::GXPeekARGB},
|
// { "GXPeekARGB", HLE_Misc::GXPeekARGB},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const SPatch OSBreakPoints[] =
|
static const SPatch OSBreakPoints[] =
|
||||||
{
|
{
|
||||||
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
|
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
|
||||||
};
|
};
|
||||||
|
|
||||||
void Patch(u32 address, const char *hle_func_name)
|
void Patch(u32 address, const char *hle_func_name)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < sizeof(OSPatches) / sizeof(SPatch); i++)
|
for (u32 i = 0; i < sizeof(OSPatches) / sizeof(SPatch); i++)
|
||||||
{
|
{
|
||||||
if (!strcmp(OSPatches[i].m_szPatchName, hle_func_name)) {
|
if (!strcmp(OSPatches[i].m_szPatchName, hle_func_name)) {
|
||||||
u32 HLEPatchValue = (1 & 0x3f) << 26;
|
u32 HLEPatchValue = (1 & 0x3f) << 26;
|
||||||
Memory::Write_U32(HLEPatchValue | i, address);
|
Memory::Write_U32(HLEPatchValue | i, address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PatchFunctions()
|
void PatchFunctions()
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < sizeof(OSPatches) / sizeof(SPatch); i++)
|
for (u32 i = 0; i < sizeof(OSPatches) / sizeof(SPatch); i++)
|
||||||
{
|
{
|
||||||
Symbol *symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName);
|
Symbol *symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName);
|
||||||
if (symbol > 0)
|
if (symbol > 0)
|
||||||
{
|
{
|
||||||
u32 HLEPatchValue = (1 & 0x3f) << 26;
|
u32 HLEPatchValue = (1 & 0x3f) << 26;
|
||||||
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
||||||
Memory::Write_U32(HLEPatchValue | i, addr);
|
Memory::Write_U32(HLEPatchValue | i, addr);
|
||||||
LOG(HLE,"Patching %s %08x", OSPatches[i].m_szPatchName, symbol->address);
|
LOG(HLE,"Patching %s %08x", OSPatches[i].m_szPatchName, symbol->address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 1; i < sizeof(OSBreakPoints) / sizeof(SPatch); i++)
|
for (size_t i = 1; i < sizeof(OSBreakPoints) / sizeof(SPatch); i++)
|
||||||
{
|
{
|
||||||
Symbol *symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName);
|
Symbol *symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName);
|
||||||
if (symbol > 0)
|
if (symbol > 0)
|
||||||
{
|
{
|
||||||
CBreakPoints::AddBreakPoint(symbol->address, false);
|
CBreakPoints::AddBreakPoint(symbol->address, false);
|
||||||
LOG(HLE,"Adding BP to %s %08x", OSBreakPoints[i].m_szPatchName, symbol->address);
|
LOG(HLE,"Adding BP to %s %08x", OSBreakPoints[i].m_szPatchName, symbol->address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CBreakPoints::AddBreakPoint(0x8000D3D0, false);
|
// CBreakPoints::AddBreakPoint(0x8000D3D0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Execute(u32 _CurrentPC, u32 _Instruction)
|
void Execute(u32 _CurrentPC, u32 _Instruction)
|
||||||
{
|
{
|
||||||
unsigned int FunctionIndex = _Instruction & 0xFFFFF;
|
unsigned int FunctionIndex = _Instruction & 0xFFFFF;
|
||||||
if ((FunctionIndex > 0) && (FunctionIndex < (sizeof(OSPatches) / sizeof(SPatch))))
|
if ((FunctionIndex > 0) && (FunctionIndex < (sizeof(OSPatches) / sizeof(SPatch))))
|
||||||
{
|
{
|
||||||
OSPatches[FunctionIndex].PatchFunction();
|
OSPatches[FunctionIndex].PatchFunction();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PanicAlert("HLE system tried to call an undefined HLE function %i.", FunctionIndex);
|
PanicAlert("HLE system tried to call an undefined HLE function %i.", FunctionIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// _dbg_assert_msg_(HLE,NPC == LR, "Broken HLE function (doesn't set NPC)", OSPatches[pos].m_szPatchName);
|
// _dbg_assert_msg_(HLE,NPC == LR, "Broken HLE function (doesn't set NPC)", OSPatches[pos].m_szPatchName);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,161 +1,161 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "HLE_OS.h"
|
#include "HLE_OS.h"
|
||||||
|
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
|
|
||||||
namespace HLE_Misc
|
namespace HLE_Misc
|
||||||
{
|
{
|
||||||
|
|
||||||
inline float F(u32 addr)
|
inline float F(u32 addr)
|
||||||
{
|
{
|
||||||
u32 mem = Memory::ReadFast32(addr);
|
u32 mem = Memory::ReadFast32(addr);
|
||||||
return *((float*)&mem);
|
return *((float*)&mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void FW(u32 addr, float x)
|
inline void FW(u32 addr, float x)
|
||||||
{
|
{
|
||||||
u32 data = *((u32*)&x);
|
u32 data = *((u32*)&x);
|
||||||
Memory::WriteUnchecked_U32(data, addr);
|
Memory::WriteUnchecked_U32(data, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnimplementedFunction()
|
void UnimplementedFunction()
|
||||||
{
|
{
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnimplementedFunctionTrue()
|
void UnimplementedFunctionTrue()
|
||||||
{
|
{
|
||||||
GPR(3) = 1;
|
GPR(3) = 1;
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnimplementedFunctionFalse()
|
void UnimplementedFunctionFalse()
|
||||||
{
|
{
|
||||||
GPR(3) = 0;
|
GPR(3) = 0;
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GXPeekZ()
|
void GXPeekZ()
|
||||||
{
|
{
|
||||||
Memory::Write_U32(0xFFFFFF, GPR(5));
|
Memory::Write_U32(0xFFFFFF, GPR(5));
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GXPeekARGB()
|
void GXPeekARGB()
|
||||||
{
|
{
|
||||||
Memory::Write_U32(0xFFFFFFFF, GPR(5));
|
Memory::Write_U32(0xFFFFFFFF, GPR(5));
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanicAlert()
|
void PanicAlert()
|
||||||
{
|
{
|
||||||
::PanicAlert("HLE: PanicAlert %08x", LR);
|
::PanicAlert("HLE: PanicAlert %08x", LR);
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// .evil_vec_cosine
|
// .evil_vec_cosine
|
||||||
void SMB_EvilVecCosine()
|
void SMB_EvilVecCosine()
|
||||||
{
|
{
|
||||||
u32 r3 = GPR(3);
|
u32 r3 = GPR(3);
|
||||||
u32 r4 = GPR(4);
|
u32 r4 = GPR(4);
|
||||||
|
|
||||||
float x1 = F(r3);
|
float x1 = F(r3);
|
||||||
float y1 = F(r3 + 4);
|
float y1 = F(r3 + 4);
|
||||||
float z1 = F(r3 + 8);
|
float z1 = F(r3 + 8);
|
||||||
|
|
||||||
float x2 = F(r4);
|
float x2 = F(r4);
|
||||||
float y2 = F(r4 + 4);
|
float y2 = F(r4 + 4);
|
||||||
float z2 = F(r4 + 8);
|
float z2 = F(r4 + 8);
|
||||||
|
|
||||||
float s1 = x1*x1 + y1*y1 + z1*z1;
|
float s1 = x1*x1 + y1*y1 + z1*z1;
|
||||||
float s2 = x2*x2 + y2*y2 + z2*z2;
|
float s2 = x2*x2 + y2*y2 + z2*z2;
|
||||||
|
|
||||||
float dot = x1*x2 + y1*y2 + z1*z2;
|
float dot = x1*x2 + y1*y2 + z1*z2;
|
||||||
|
|
||||||
rPS0(1) = dot / sqrtf(s1 * s2);
|
rPS0(1) = dot / sqrtf(s1 * s2);
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMB_EvilNormalize()
|
void SMB_EvilNormalize()
|
||||||
{
|
{
|
||||||
u32 r3 = GPR(3);
|
u32 r3 = GPR(3);
|
||||||
float x = F(r3);
|
float x = F(r3);
|
||||||
float y = F(r3 + 4);
|
float y = F(r3 + 4);
|
||||||
float z = F(r3 + 8);
|
float z = F(r3 + 8);
|
||||||
float inv_len = 1.0f / sqrtf(x*x + y*y + z*z);
|
float inv_len = 1.0f / sqrtf(x*x + y*y + z*z);
|
||||||
x *= inv_len;
|
x *= inv_len;
|
||||||
y *= inv_len;
|
y *= inv_len;
|
||||||
z *= inv_len;
|
z *= inv_len;
|
||||||
FW(r3, x);
|
FW(r3, x);
|
||||||
FW(r3 + 4, y);
|
FW(r3 + 4, y);
|
||||||
FW(r3 + 8, z);
|
FW(r3 + 8, z);
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMB_evil_vec_setlength()
|
void SMB_evil_vec_setlength()
|
||||||
{
|
{
|
||||||
u32 r3 = GPR(3);
|
u32 r3 = GPR(3);
|
||||||
u32 r4 = GPR(4);
|
u32 r4 = GPR(4);
|
||||||
float x = F(r3);
|
float x = F(r3);
|
||||||
float y = F(r3 + 4);
|
float y = F(r3 + 4);
|
||||||
float z = F(r3 + 8);
|
float z = F(r3 + 8);
|
||||||
float inv_len = (float)(rPS0(1) / sqrt(x*x + y*y + z*z));
|
float inv_len = (float)(rPS0(1) / sqrt(x*x + y*y + z*z));
|
||||||
x *= inv_len;
|
x *= inv_len;
|
||||||
y *= inv_len;
|
y *= inv_len;
|
||||||
z *= inv_len;
|
z *= inv_len;
|
||||||
FW(r4, x);
|
FW(r4, x);
|
||||||
FW(r4 + 4, y);
|
FW(r4 + 4, y);
|
||||||
FW(r4 + 8, z);
|
FW(r4 + 8, z);
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SMB_sqrt_internal()
|
void SMB_sqrt_internal()
|
||||||
{
|
{
|
||||||
double f = sqrt(rPS0(1));
|
double f = sqrt(rPS0(1));
|
||||||
rPS0(0) = rPS0(1);
|
rPS0(0) = rPS0(1);
|
||||||
rPS1(0) = rPS0(1);
|
rPS1(0) = rPS0(1);
|
||||||
rPS0(1) = f;
|
rPS0(1) = f;
|
||||||
rPS1(1) = f;
|
rPS1(1) = f;
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMB_rsqrt_internal()
|
void SMB_rsqrt_internal()
|
||||||
{
|
{
|
||||||
double f = 1.0 / sqrt(rPS0(1));
|
double f = 1.0 / sqrt(rPS0(1));
|
||||||
rPS0(1) = f;
|
rPS0(1) = f;
|
||||||
rPS1(1) = f;
|
rPS1(1) = f;
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMB_atan2()
|
void SMB_atan2()
|
||||||
{
|
{
|
||||||
// in: f1 = x, f2 = y
|
// in: f1 = x, f2 = y
|
||||||
// out: r3 = angle
|
// out: r3 = angle
|
||||||
double angle = atan2(rPS0(1), rPS0(2));
|
double angle = atan2(rPS0(1), rPS0(2));
|
||||||
int angle_fixpt = (int)(angle / 3.14159 * 32767);
|
int angle_fixpt = (int)(angle / 3.14159 * 32767);
|
||||||
if (angle_fixpt < -32767) angle_fixpt = -32767;
|
if (angle_fixpt < -32767) angle_fixpt = -32767;
|
||||||
if (angle_fixpt > 32767) angle_fixpt = 32767;
|
if (angle_fixpt > 32767) angle_fixpt = 32767;
|
||||||
GPR(3) = angle_fixpt;
|
GPR(3) = angle_fixpt;
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,148 +1,148 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "HLE_OS.h"
|
#include "HLE_OS.h"
|
||||||
|
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
|
|
||||||
namespace HLE_OS
|
namespace HLE_OS
|
||||||
{
|
{
|
||||||
|
|
||||||
void GetStringVA(std::string& _rOutBuffer);
|
void GetStringVA(std::string& _rOutBuffer);
|
||||||
|
|
||||||
void HLE_OSPanic()
|
void HLE_OSPanic()
|
||||||
{
|
{
|
||||||
std::string Error;
|
std::string Error;
|
||||||
GetStringVA(Error);
|
GetStringVA(Error);
|
||||||
|
|
||||||
PanicAlert("OSPanic: %s", Error.c_str());
|
PanicAlert("OSPanic: %s", Error.c_str());
|
||||||
LOG(OSREPORT,"(PC=%08x), OSPanic: %s", LR, Error.c_str());
|
LOG(OSREPORT,"(PC=%08x), OSPanic: %s", LR, Error.c_str());
|
||||||
|
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HLE_OSReport()
|
void HLE_OSReport()
|
||||||
{
|
{
|
||||||
std::string ReportMessage;
|
std::string ReportMessage;
|
||||||
GetStringVA(ReportMessage);
|
GetStringVA(ReportMessage);
|
||||||
|
|
||||||
|
|
||||||
// PanicAlert("(PC=%08x) OSReport: %s", LR, ReportMessage.c_str());
|
// PanicAlert("(PC=%08x) OSReport: %s", LR, ReportMessage.c_str());
|
||||||
|
|
||||||
LOG(OSREPORT,"(PC=%08x) OSReport: %s", LR, ReportMessage.c_str());
|
LOG(OSREPORT,"(PC=%08x) OSReport: %s", LR, ReportMessage.c_str());
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HLE_vprintf()
|
void HLE_vprintf()
|
||||||
{
|
{
|
||||||
std::string ReportMessage;
|
std::string ReportMessage;
|
||||||
GetStringVA(ReportMessage);
|
GetStringVA(ReportMessage);
|
||||||
|
|
||||||
LOG(OSREPORT,"(PC=%08x) VPrintf: %s", LR, ReportMessage.c_str());
|
LOG(OSREPORT,"(PC=%08x) VPrintf: %s", LR, ReportMessage.c_str());
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HLE_printf()
|
void HLE_printf()
|
||||||
{
|
{
|
||||||
std::string ReportMessage;
|
std::string ReportMessage;
|
||||||
GetStringVA(ReportMessage);
|
GetStringVA(ReportMessage);
|
||||||
|
|
||||||
LOG(OSREPORT,"(PC=%08x) Printf: %s ", LR, ReportMessage.c_str());
|
LOG(OSREPORT,"(PC=%08x) Printf: %s ", LR, ReportMessage.c_str());
|
||||||
NPC = LR;
|
NPC = LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetStringVA(std::string& _rOutBuffer)
|
void GetStringVA(std::string& _rOutBuffer)
|
||||||
{
|
{
|
||||||
_rOutBuffer = "";
|
_rOutBuffer = "";
|
||||||
char ArgumentBuffer[256];
|
char ArgumentBuffer[256];
|
||||||
u32 ParameterCounter = 4;
|
u32 ParameterCounter = 4;
|
||||||
u32 FloatingParameterCounter = 1;
|
u32 FloatingParameterCounter = 1;
|
||||||
char* pString = (char*)Memory::GetPointer(GPR(3));
|
char* pString = (char*)Memory::GetPointer(GPR(3));
|
||||||
if (!pString) {
|
if (!pString) {
|
||||||
//PanicAlert("Invalid GetStringVA call");
|
//PanicAlert("Invalid GetStringVA call");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while(*pString)
|
while(*pString)
|
||||||
{
|
{
|
||||||
if (*pString == '%')
|
if (*pString == '%')
|
||||||
{
|
{
|
||||||
char* pArgument = ArgumentBuffer;
|
char* pArgument = ArgumentBuffer;
|
||||||
*pArgument++ = *pString++;
|
*pArgument++ = *pString++;
|
||||||
while(*pString < 'A' || *pString > 'z' || *pString == 'l' || *pString == '-')
|
while(*pString < 'A' || *pString > 'z' || *pString == 'l' || *pString == '-')
|
||||||
*pArgument++ = *pString++;
|
*pArgument++ = *pString++;
|
||||||
|
|
||||||
*pArgument++ = *pString;
|
*pArgument++ = *pString;
|
||||||
*pArgument = NULL;
|
*pArgument = NULL;
|
||||||
|
|
||||||
u32 Parameter;
|
u32 Parameter;
|
||||||
if (ParameterCounter > 10)
|
if (ParameterCounter > 10)
|
||||||
{
|
{
|
||||||
Parameter = Memory::Read_U32(GPR(1) + 0x8 + ((ParameterCounter - 11) * 4));
|
Parameter = Memory::Read_U32(GPR(1) + 0x8 + ((ParameterCounter - 11) * 4));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Parameter = GPR(ParameterCounter);
|
Parameter = GPR(ParameterCounter);
|
||||||
}
|
}
|
||||||
ParameterCounter++;
|
ParameterCounter++;
|
||||||
|
|
||||||
switch(*pString)
|
switch(*pString)
|
||||||
{
|
{
|
||||||
case 's':
|
case 's':
|
||||||
_rOutBuffer += StringFromFormat(ArgumentBuffer, (char*)Memory::GetPointer(Parameter));
|
_rOutBuffer += StringFromFormat(ArgumentBuffer, (char*)Memory::GetPointer(Parameter));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'i':
|
case 'i':
|
||||||
{
|
{
|
||||||
//u64 Double = Memory::Read_U64(Parameter);
|
//u64 Double = Memory::Read_U64(Parameter);
|
||||||
_rOutBuffer += StringFromFormat(ArgumentBuffer, Parameter);
|
_rOutBuffer += StringFromFormat(ArgumentBuffer, Parameter);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
{
|
{
|
||||||
_rOutBuffer += StringFromFormat(ArgumentBuffer,
|
_rOutBuffer += StringFromFormat(ArgumentBuffer,
|
||||||
rPS0(FloatingParameterCounter));
|
rPS0(FloatingParameterCounter));
|
||||||
FloatingParameterCounter++;
|
FloatingParameterCounter++;
|
||||||
ParameterCounter--;
|
ParameterCounter--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_rOutBuffer += StringFromFormat(ArgumentBuffer, Parameter);
|
_rOutBuffer += StringFromFormat(ArgumentBuffer, Parameter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pString++;
|
pString++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_rOutBuffer += StringFromFormat("%c", *pString);
|
_rOutBuffer += StringFromFormat("%c", *pString);
|
||||||
pString++;
|
pString++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(_rOutBuffer[_rOutBuffer.length() - 1] == '\n')
|
if(_rOutBuffer[_rOutBuffer.length() - 1] == '\n')
|
||||||
_rOutBuffer.resize(_rOutBuffer.length() - 1);
|
_rOutBuffer.resize(_rOutBuffer.length() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,361 +1,361 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
// This file is ONLY about disc streaming. It's a bit unfortunately named.
|
// This file is ONLY about disc streaming. It's a bit unfortunately named.
|
||||||
// For the rest of the audio stuff, including the "real" AI, see DSP.cpp/h.
|
// For the rest of the audio stuff, including the "real" AI, see DSP.cpp/h.
|
||||||
|
|
||||||
// AI disc streaming is handled completely separately from the rest of the
|
// AI disc streaming is handled completely separately from the rest of the
|
||||||
// audio processing. In short, it simply streams audio directly from disc
|
// audio processing. In short, it simply streams audio directly from disc
|
||||||
// out through the speakers.
|
// out through the speakers.
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
#include "StreamADPCM.H"
|
#include "StreamADPCM.H"
|
||||||
#include "AudioInterface.h"
|
#include "AudioInterface.h"
|
||||||
|
|
||||||
#include "CPU.h"
|
#include "CPU.h"
|
||||||
#include "PeripheralInterface.h"
|
#include "PeripheralInterface.h"
|
||||||
#include "DVDInterface.h"
|
#include "DVDInterface.h"
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "../CoreTiming.h"
|
#include "../CoreTiming.h"
|
||||||
#include "../HW/SystemTimers.h"
|
#include "../HW/SystemTimers.h"
|
||||||
|
|
||||||
namespace AudioInterface
|
namespace AudioInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
// internal hardware addresses
|
// internal hardware addresses
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
AI_CONTROL_REGISTER = 0x6C00,
|
AI_CONTROL_REGISTER = 0x6C00,
|
||||||
AI_VOLUME_REGISTER = 0x6C04,
|
AI_VOLUME_REGISTER = 0x6C04,
|
||||||
AI_SAMPLE_COUNTER = 0x6C08,
|
AI_SAMPLE_COUNTER = 0x6C08,
|
||||||
AI_INTERRUPT_TIMING = 0x6C0C,
|
AI_INTERRUPT_TIMING = 0x6C0C,
|
||||||
};
|
};
|
||||||
|
|
||||||
// AI Control Register
|
// AI Control Register
|
||||||
union AICR
|
union AICR
|
||||||
{
|
{
|
||||||
AICR() { hex = 0;}
|
AICR() { hex = 0;}
|
||||||
AICR(u32 _hex) { hex = _hex;}
|
AICR(u32 _hex) { hex = _hex;}
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned PSTAT : 1; // sample counter/playback enable
|
unsigned PSTAT : 1; // sample counter/playback enable
|
||||||
unsigned AFR : 1; // 0=32khz 1=48khz
|
unsigned AFR : 1; // 0=32khz 1=48khz
|
||||||
unsigned AIINTMSK : 1; // 0=interrupt masked 1=interrupt enabled
|
unsigned AIINTMSK : 1; // 0=interrupt masked 1=interrupt enabled
|
||||||
unsigned AIINT : 1; // audio interrupt status
|
unsigned AIINT : 1; // audio interrupt status
|
||||||
unsigned AIINTVLD : 1; // This bit controls whether AIINT is affected by the AIIT register
|
unsigned AIINTVLD : 1; // This bit controls whether AIINT is affected by the AIIT register
|
||||||
// matching AISLRCNT. Once set, AIINT will hold
|
// matching AISLRCNT. Once set, AIINT will hold
|
||||||
unsigned SCRESET : 1; // write to reset counter
|
unsigned SCRESET : 1; // write to reset counter
|
||||||
unsigned DSPFR : 1; // DSP Frequency (0=32khz 1=48khz)
|
unsigned DSPFR : 1; // DSP Frequency (0=32khz 1=48khz)
|
||||||
unsigned :25;
|
unsigned :25;
|
||||||
};
|
};
|
||||||
u32 hex;
|
u32 hex;
|
||||||
};
|
};
|
||||||
|
|
||||||
// AI m_Volume Register
|
// AI m_Volume Register
|
||||||
union AIVR
|
union AIVR
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned leftVolume : 8;
|
unsigned leftVolume : 8;
|
||||||
unsigned rightVolume : 8;
|
unsigned rightVolume : 8;
|
||||||
unsigned : 16;
|
unsigned : 16;
|
||||||
};
|
};
|
||||||
u32 hex;
|
u32 hex;
|
||||||
};
|
};
|
||||||
|
|
||||||
// AudioInterface-Registers
|
// AudioInterface-Registers
|
||||||
struct SAudioRegister
|
struct SAudioRegister
|
||||||
{
|
{
|
||||||
AICR m_Control;
|
AICR m_Control;
|
||||||
AIVR m_Volume;
|
AIVR m_Volume;
|
||||||
u32 m_SampleCounter;
|
u32 m_SampleCounter;
|
||||||
u32 m_InterruptTiming;
|
u32 m_InterruptTiming;
|
||||||
};
|
};
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
static SAudioRegister g_AudioRegister;
|
static SAudioRegister g_AudioRegister;
|
||||||
static u64 g_LastCPUTime = 0;
|
static u64 g_LastCPUTime = 0;
|
||||||
static int g_SampleRate = 32000;
|
static int g_SampleRate = 32000;
|
||||||
static int g_DSPSampleRate = 32000;
|
static int g_DSPSampleRate = 32000;
|
||||||
static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL;
|
static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL;
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
p.Do(g_AudioRegister);
|
p.Do(g_AudioRegister);
|
||||||
p.Do(g_LastCPUTime);
|
p.Do(g_LastCPUTime);
|
||||||
p.Do(g_SampleRate);
|
p.Do(g_SampleRate);
|
||||||
p.Do(g_DSPSampleRate);
|
p.Do(g_DSPSampleRate);
|
||||||
p.Do(g_CPUCyclesPerSample);
|
p.Do(g_CPUCyclesPerSample);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateAudioInterrupt();
|
void GenerateAudioInterrupt();
|
||||||
void UpdateInterrupts();
|
void UpdateInterrupts();
|
||||||
void IncreaseSampleCount(const u32 _uAmount);
|
void IncreaseSampleCount(const u32 _uAmount);
|
||||||
void ReadStreamBlock(short* _pPCM);
|
void ReadStreamBlock(short* _pPCM);
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
g_AudioRegister.m_SampleCounter = 0;
|
g_AudioRegister.m_SampleCounter = 0;
|
||||||
g_AudioRegister.m_Control.AFR = 1;
|
g_AudioRegister.m_Control.AFR = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Read32(u32& _rReturnValue, const u32 _Address)
|
void Read32(u32& _rReturnValue, const u32 _Address)
|
||||||
{
|
{
|
||||||
//__AI_SRC_INIT compares CC006C08 to zero, loops if 2
|
//__AI_SRC_INIT compares CC006C08 to zero, loops if 2
|
||||||
switch (_Address & 0xFFFF)
|
switch (_Address & 0xFFFF)
|
||||||
{
|
{
|
||||||
case AI_CONTROL_REGISTER: //0x6C00
|
case AI_CONTROL_REGISTER: //0x6C00
|
||||||
LOGV(AUDIO_INTERFACE, 1, "AudioInterface(R) 0x%08x", _Address);
|
LOGV(AUDIO_INTERFACE, 1, "AudioInterface(R) 0x%08x", _Address);
|
||||||
_rReturnValue = g_AudioRegister.m_Control.hex;
|
_rReturnValue = g_AudioRegister.m_Control.hex;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Sample Rate (AIGetDSPSampleRate)
|
// Sample Rate (AIGetDSPSampleRate)
|
||||||
// 32bit state (highest bit PlayState) // AIGetStreamPlayState
|
// 32bit state (highest bit PlayState) // AIGetStreamPlayState
|
||||||
case AI_VOLUME_REGISTER: //0x6C04
|
case AI_VOLUME_REGISTER: //0x6C04
|
||||||
LOGV(AUDIO_INTERFACE, 1, "AudioInterface(R) 0x%08x", _Address);
|
LOGV(AUDIO_INTERFACE, 1, "AudioInterface(R) 0x%08x", _Address);
|
||||||
_rReturnValue = g_AudioRegister.m_Volume.hex;
|
_rReturnValue = g_AudioRegister.m_Volume.hex;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case AI_SAMPLE_COUNTER: //0x6C08
|
case AI_SAMPLE_COUNTER: //0x6C08
|
||||||
_rReturnValue = g_AudioRegister.m_SampleCounter;
|
_rReturnValue = g_AudioRegister.m_SampleCounter;
|
||||||
if (g_AudioRegister.m_Control.PSTAT)
|
if (g_AudioRegister.m_Control.PSTAT)
|
||||||
g_AudioRegister.m_SampleCounter++; // FAKE: but this is a must
|
g_AudioRegister.m_SampleCounter++; // FAKE: but this is a must
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case AI_INTERRUPT_TIMING:
|
case AI_INTERRUPT_TIMING:
|
||||||
// When sample counter reaches the value of this register, the interrupt AIINT should
|
// When sample counter reaches the value of this register, the interrupt AIINT should
|
||||||
// fire.
|
// fire.
|
||||||
LOGV(AUDIO_INTERFACE, 1, "AudioInterface(R) 0x%08x", _Address);
|
LOGV(AUDIO_INTERFACE, 1, "AudioInterface(R) 0x%08x", _Address);
|
||||||
_rReturnValue = g_AudioRegister.m_InterruptTiming;
|
_rReturnValue = g_AudioRegister.m_InterruptTiming;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
|
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
|
||||||
_dbg_assert_msg_(AUDIO_INTERFACE, 0, "AudioInterface - Read from ???");
|
_dbg_assert_msg_(AUDIO_INTERFACE, 0, "AudioInterface - Read from ???");
|
||||||
_rReturnValue = 0;
|
_rReturnValue = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write32(const u32 _Value, const u32 _Address)
|
void Write32(const u32 _Value, const u32 _Address)
|
||||||
{
|
{
|
||||||
switch (_Address & 0xFFFF)
|
switch (_Address & 0xFFFF)
|
||||||
{
|
{
|
||||||
case AI_CONTROL_REGISTER:
|
case AI_CONTROL_REGISTER:
|
||||||
{
|
{
|
||||||
AICR tmpAICtrl(_Value);
|
AICR tmpAICtrl(_Value);
|
||||||
|
|
||||||
g_AudioRegister.m_Control.AIINTMSK = tmpAICtrl.AIINTMSK;
|
g_AudioRegister.m_Control.AIINTMSK = tmpAICtrl.AIINTMSK;
|
||||||
g_AudioRegister.m_Control.AIINTVLD = tmpAICtrl.AIINTVLD;
|
g_AudioRegister.m_Control.AIINTVLD = tmpAICtrl.AIINTVLD;
|
||||||
|
|
||||||
// Set frequency
|
// Set frequency
|
||||||
if (tmpAICtrl.AFR != g_AudioRegister.m_Control.AFR)
|
if (tmpAICtrl.AFR != g_AudioRegister.m_Control.AFR)
|
||||||
{
|
{
|
||||||
LOG(AUDIO_INTERFACE, "Change Freq to %s", tmpAICtrl.AFR ? "48khz":"32khz");
|
LOG(AUDIO_INTERFACE, "Change Freq to %s", tmpAICtrl.AFR ? "48khz":"32khz");
|
||||||
g_AudioRegister.m_Control.AFR = tmpAICtrl.AFR;
|
g_AudioRegister.m_Control.AFR = tmpAICtrl.AFR;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_SampleRate = tmpAICtrl.AFR ? 32000 : 48000;
|
g_SampleRate = tmpAICtrl.AFR ? 32000 : 48000;
|
||||||
g_DSPSampleRate = tmpAICtrl.DSPFR ? 32000 : 48000;
|
g_DSPSampleRate = tmpAICtrl.DSPFR ? 32000 : 48000;
|
||||||
// PanicAlert("Sample rate %i %i", g_Aui, g_SampleRate);
|
// PanicAlert("Sample rate %i %i", g_Aui, g_SampleRate);
|
||||||
|
|
||||||
g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_SampleRate;
|
g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_SampleRate;
|
||||||
|
|
||||||
// Streaming counter
|
// Streaming counter
|
||||||
if (tmpAICtrl.PSTAT != g_AudioRegister.m_Control.PSTAT)
|
if (tmpAICtrl.PSTAT != g_AudioRegister.m_Control.PSTAT)
|
||||||
{
|
{
|
||||||
LOG(AUDIO_INTERFACE, "Change StreamingCounter to %s", tmpAICtrl.PSTAT ? "startet":"stopped");
|
LOG(AUDIO_INTERFACE, "Change StreamingCounter to %s", tmpAICtrl.PSTAT ? "startet":"stopped");
|
||||||
g_AudioRegister.m_Control.PSTAT = tmpAICtrl.PSTAT;
|
g_AudioRegister.m_Control.PSTAT = tmpAICtrl.PSTAT;
|
||||||
|
|
||||||
g_LastCPUTime = CoreTiming::GetTicks();
|
g_LastCPUTime = CoreTiming::GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
// AI Interrupt
|
// AI Interrupt
|
||||||
if (tmpAICtrl.AIINT)
|
if (tmpAICtrl.AIINT)
|
||||||
{
|
{
|
||||||
LOG(AUDIO_INTERFACE, "Clear AI Interrupt");
|
LOG(AUDIO_INTERFACE, "Clear AI Interrupt");
|
||||||
g_AudioRegister.m_Control.AIINT = 0;
|
g_AudioRegister.m_Control.AIINT = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample Count Reset
|
// Sample Count Reset
|
||||||
if (tmpAICtrl.SCRESET)
|
if (tmpAICtrl.SCRESET)
|
||||||
{
|
{
|
||||||
LOGV(AUDIO_INTERFACE, 1, "Reset SampleCounter");
|
LOGV(AUDIO_INTERFACE, 1, "Reset SampleCounter");
|
||||||
g_AudioRegister.m_SampleCounter = 0;
|
g_AudioRegister.m_SampleCounter = 0;
|
||||||
g_AudioRegister.m_Control.SCRESET = 0;
|
g_AudioRegister.m_Control.SCRESET = 0;
|
||||||
|
|
||||||
// set PSTAT = 0 too ? at least the reversed look like this
|
// set PSTAT = 0 too ? at least the reversed look like this
|
||||||
|
|
||||||
g_LastCPUTime = CoreTiming::GetTicks();
|
g_LastCPUTime = CoreTiming::GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
g_AudioRegister.m_Control = tmpAICtrl;
|
g_AudioRegister.m_Control = tmpAICtrl;
|
||||||
|
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AI_VOLUME_REGISTER:
|
case AI_VOLUME_REGISTER:
|
||||||
g_AudioRegister.m_Volume.hex = _Value;
|
g_AudioRegister.m_Volume.hex = _Value;
|
||||||
LOGV(AUDIO_INTERFACE, 1, "Set m_Volume: left(%i) right(%i)", g_AudioRegister.m_Volume.leftVolume, g_AudioRegister.m_Volume.rightVolume);
|
LOGV(AUDIO_INTERFACE, 1, "Set m_Volume: left(%i) right(%i)", g_AudioRegister.m_Volume.leftVolume, g_AudioRegister.m_Volume.rightVolume);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AI_SAMPLE_COUNTER:
|
case AI_SAMPLE_COUNTER:
|
||||||
// _dbg_assert_msg_(AUDIO_INTERFACE, 0, "AudioInterface - m_SampleCounter is Read only");
|
// _dbg_assert_msg_(AUDIO_INTERFACE, 0, "AudioInterface - m_SampleCounter is Read only");
|
||||||
g_AudioRegister.m_SampleCounter = _Value;
|
g_AudioRegister.m_SampleCounter = _Value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AI_INTERRUPT_TIMING:
|
case AI_INTERRUPT_TIMING:
|
||||||
g_AudioRegister.m_InterruptTiming = _Value;
|
g_AudioRegister.m_InterruptTiming = _Value;
|
||||||
LOG(AUDIO_INTERFACE, "Set AudioInterrupt: 0x%08x Samples", g_AudioRegister.m_InterruptTiming);
|
LOG(AUDIO_INTERFACE, "Set AudioInterrupt: 0x%08x Samples", g_AudioRegister.m_InterruptTiming);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PanicAlert("AudioInterface unknown write");
|
PanicAlert("AudioInterface unknown write");
|
||||||
_dbg_assert_msg_(AUDIO_INTERFACE,0,"AudioInterface - Write to ??? %08x", _Address);
|
_dbg_assert_msg_(AUDIO_INTERFACE,0,"AudioInterface - Write to ??? %08x", _Address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateInterrupts()
|
void UpdateInterrupts()
|
||||||
{
|
{
|
||||||
if (g_AudioRegister.m_Control.AIINT & g_AudioRegister.m_Control.AIINTMSK)
|
if (g_AudioRegister.m_Control.AIINT & g_AudioRegister.m_Control.AIINTMSK)
|
||||||
{
|
{
|
||||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_AUDIO, true);
|
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_AUDIO, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_AUDIO, false);
|
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_AUDIO, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateAudioInterrupt()
|
void GenerateAudioInterrupt()
|
||||||
{
|
{
|
||||||
g_AudioRegister.m_Control.AIINT = 1;
|
g_AudioRegister.m_Control.AIINT = 1;
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback for the disc streaming
|
// Callback for the disc streaming
|
||||||
// WARNING - called from audio thread
|
// WARNING - called from audio thread
|
||||||
u32 Callback_GetStreaming(short* _pDestBuffer, u32 _numSamples)
|
u32 Callback_GetStreaming(short* _pDestBuffer, u32 _numSamples)
|
||||||
{
|
{
|
||||||
if (g_AudioRegister.m_Control.PSTAT && !CCPU::IsStepping())
|
if (g_AudioRegister.m_Control.PSTAT && !CCPU::IsStepping())
|
||||||
{
|
{
|
||||||
static int pos = 0;
|
static int pos = 0;
|
||||||
static short pcm[28*2];
|
static short pcm[28*2];
|
||||||
const int lvolume = g_AudioRegister.m_Volume.leftVolume;
|
const int lvolume = g_AudioRegister.m_Volume.leftVolume;
|
||||||
const int rvolume = g_AudioRegister.m_Volume.rightVolume;
|
const int rvolume = g_AudioRegister.m_Volume.rightVolume;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < _numSamples; i++)
|
for (unsigned int i = 0; i < _numSamples; i++)
|
||||||
{
|
{
|
||||||
if (pos == 0)
|
if (pos == 0)
|
||||||
{
|
{
|
||||||
ReadStreamBlock(pcm);
|
ReadStreamBlock(pcm);
|
||||||
}
|
}
|
||||||
|
|
||||||
*_pDestBuffer++ = (pcm[pos*2] * lvolume) >> 8;
|
*_pDestBuffer++ = (pcm[pos*2] * lvolume) >> 8;
|
||||||
*_pDestBuffer++ = (pcm[pos*2+1] * rvolume) >> 8;
|
*_pDestBuffer++ = (pcm[pos*2+1] * rvolume) >> 8;
|
||||||
|
|
||||||
pos++;
|
pos++;
|
||||||
if (pos == 28)
|
if (pos == 28)
|
||||||
{
|
{
|
||||||
pos = 0;
|
pos = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < _numSamples * 2; i++)
|
for (unsigned int i = 0; i < _numSamples * 2; i++)
|
||||||
{
|
{
|
||||||
_pDestBuffer[i] = 0; //silence!
|
_pDestBuffer[i] = 0; //silence!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _numSamples;
|
return _numSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARNING - called from audio thread
|
// WARNING - called from audio thread
|
||||||
void ReadStreamBlock(short *_pPCM)
|
void ReadStreamBlock(short *_pPCM)
|
||||||
{
|
{
|
||||||
char tempADPCM[32];
|
char tempADPCM[32];
|
||||||
if (DVDInterface::DVDReadADPCM((u8*)tempADPCM, 32))
|
if (DVDInterface::DVDReadADPCM((u8*)tempADPCM, 32))
|
||||||
{
|
{
|
||||||
NGCADPCM::DecodeBlock(_pPCM, (u8*)tempADPCM);
|
NGCADPCM::DecodeBlock(_pPCM, (u8*)tempADPCM);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int j=0; j<28; j++)
|
for (int j=0; j<28; j++)
|
||||||
{
|
{
|
||||||
*_pPCM++ = 0;
|
*_pPCM++ = 0;
|
||||||
*_pPCM++ = 0;
|
*_pPCM++ = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// COMMENT:
|
// COMMENT:
|
||||||
// our whole streaming code is "faked" ... so it shouldn't increase the sample counter
|
// our whole streaming code is "faked" ... so it shouldn't increase the sample counter
|
||||||
// streaming will never work correctly this way, but at least the program will think all is alright.
|
// streaming will never work correctly this way, but at least the program will think all is alright.
|
||||||
|
|
||||||
// This call must not be done wihout going through CoreTiming's threadsafe option.
|
// This call must not be done wihout going through CoreTiming's threadsafe option.
|
||||||
// IncreaseSampleCount(28);
|
// IncreaseSampleCount(28);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IncreaseSampleCount(const u32 _iAmount)
|
void IncreaseSampleCount(const u32 _iAmount)
|
||||||
{
|
{
|
||||||
if (g_AudioRegister.m_Control.PSTAT)
|
if (g_AudioRegister.m_Control.PSTAT)
|
||||||
{
|
{
|
||||||
g_AudioRegister.m_SampleCounter += _iAmount;
|
g_AudioRegister.m_SampleCounter += _iAmount;
|
||||||
if (g_AudioRegister.m_Control.AIINTVLD &&
|
if (g_AudioRegister.m_Control.AIINTVLD &&
|
||||||
(g_AudioRegister.m_SampleCounter >= g_AudioRegister.m_InterruptTiming))
|
(g_AudioRegister.m_SampleCounter >= g_AudioRegister.m_InterruptTiming))
|
||||||
{
|
{
|
||||||
GenerateAudioInterrupt();
|
GenerateAudioInterrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetAISampleRate()
|
u32 GetAISampleRate()
|
||||||
{
|
{
|
||||||
return g_SampleRate;
|
return g_SampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetDSPSampleRate()
|
u32 GetDSPSampleRate()
|
||||||
{
|
{
|
||||||
return g_DSPSampleRate;
|
return g_DSPSampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
// update timer
|
// update timer
|
||||||
if (g_AudioRegister.m_Control.PSTAT)
|
if (g_AudioRegister.m_Control.PSTAT)
|
||||||
{
|
{
|
||||||
const u64 Diff = CoreTiming::GetTicks() - g_LastCPUTime;
|
const u64 Diff = CoreTiming::GetTicks() - g_LastCPUTime;
|
||||||
if (Diff > g_CPUCyclesPerSample)
|
if (Diff > g_CPUCyclesPerSample)
|
||||||
{
|
{
|
||||||
const u32 Samples = static_cast<u32>(Diff / g_CPUCyclesPerSample);
|
const u32 Samples = static_cast<u32>(Diff / g_CPUCyclesPerSample);
|
||||||
g_LastCPUTime += Samples * g_CPUCyclesPerSample;
|
g_LastCPUTime += Samples * g_CPUCyclesPerSample;
|
||||||
IncreaseSampleCount(Samples);
|
IncreaseSampleCount(Samples);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace AudioInterface
|
} // end of namespace AudioInterface
|
||||||
|
|
||||||
|
|
|
@ -1,237 +1,237 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
|
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "../Host.h"
|
#include "../Host.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
#include "CPU.h"
|
#include "CPU.h"
|
||||||
#include "CPUCompare.h"
|
#include "CPUCompare.h"
|
||||||
|
|
||||||
#include "../Debugger/Debugger_BreakPoints.h"
|
#include "../Debugger/Debugger_BreakPoints.h"
|
||||||
|
|
||||||
using namespace PowerPC;
|
using namespace PowerPC;
|
||||||
namespace {
|
namespace {
|
||||||
static bool g_Branch;
|
static bool g_Branch;
|
||||||
static Common::Event m_StepEvent;
|
static Common::Event m_StepEvent;
|
||||||
static Common::Event *m_SyncEvent;
|
static Common::Event *m_SyncEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPU::Init()
|
void CCPU::Init()
|
||||||
{
|
{
|
||||||
m_StepEvent.Init();
|
m_StepEvent.Init();
|
||||||
PowerPC::Init();
|
PowerPC::Init();
|
||||||
m_SyncEvent = 0;
|
m_SyncEvent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPU::Shutdown()
|
void CCPU::Shutdown()
|
||||||
{
|
{
|
||||||
PowerPC::Shutdown();
|
PowerPC::Shutdown();
|
||||||
m_StepEvent.Shutdown();
|
m_StepEvent.Shutdown();
|
||||||
m_SyncEvent = 0;
|
m_SyncEvent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPU::Run()
|
void CCPU::Run()
|
||||||
{
|
{
|
||||||
Host_UpdateDisasmDialog();
|
Host_UpdateDisasmDialog();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
switch(PowerPC::state) {
|
switch(PowerPC::state) {
|
||||||
case CPU_RUNNING:
|
case CPU_RUNNING:
|
||||||
//1: enter a fast runloop
|
//1: enter a fast runloop
|
||||||
PowerPC::RunLoop();
|
PowerPC::RunLoop();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPU_RUNNINGDEBUG:
|
case CPU_RUNNINGDEBUG:
|
||||||
//1: check for cpucompare
|
//1: check for cpucompare
|
||||||
/*
|
/*
|
||||||
if (CPUCompare::IsEnabled() && g_Branch)
|
if (CPUCompare::IsEnabled() && g_Branch)
|
||||||
{
|
{
|
||||||
g_Branch = false;
|
g_Branch = false;
|
||||||
CPUCompare::Sync();
|
CPUCompare::Sync();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
//2: check for breakpoint
|
//2: check for breakpoint
|
||||||
if (CBreakPoints::IsAddressBreakPoint(PC))
|
if (CBreakPoints::IsAddressBreakPoint(PC))
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "Hit Breakpoint - %08x", PC);
|
LOG(GEKKO, "Hit Breakpoint - %08x", PC);
|
||||||
EnableStepping(true);
|
EnableStepping(true);
|
||||||
if (CBreakPoints::IsTempBreakPoint(PC))
|
if (CBreakPoints::IsTempBreakPoint(PC))
|
||||||
CBreakPoints::RemoveBreakPoint(PC);
|
CBreakPoints::RemoveBreakPoint(PC);
|
||||||
|
|
||||||
Host_UpdateDisasmDialog();
|
Host_UpdateDisasmDialog();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if (!Core::g_CoreStartupParameter.bUseJIT && CBreakPoints::GetBreakCount() == PowerPC::ppcState.DebugCount)
|
/* if (!Core::g_CoreStartupParameter.bUseJIT && CBreakPoints::GetBreakCount() == PowerPC::ppcState.DebugCount)
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "Hit DebugCount breakpoint - %i", PowerPC::ppcState.DebugCount);
|
LOG(GEKKO, "Hit DebugCount breakpoint - %i", PowerPC::ppcState.DebugCount);
|
||||||
EnableStepping(true);
|
EnableStepping(true);
|
||||||
break;
|
break;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
//3: do a step
|
//3: do a step
|
||||||
PowerPC::SingleStep();
|
PowerPC::SingleStep();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPU_STEPPING:
|
case CPU_STEPPING:
|
||||||
//1: wait for step command..
|
//1: wait for step command..
|
||||||
|
|
||||||
m_StepEvent.Wait();
|
m_StepEvent.Wait();
|
||||||
if (state == CPU_POWERDOWN)
|
if (state == CPU_POWERDOWN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//2: check for cpu compare
|
//2: check for cpu compare
|
||||||
if (CPUCompare::IsEnabled() && g_Branch)
|
if (CPUCompare::IsEnabled() && g_Branch)
|
||||||
{
|
{
|
||||||
g_Branch = false;
|
g_Branch = false;
|
||||||
CPUCompare::Sync();
|
CPUCompare::Sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
//3: do a step
|
//3: do a step
|
||||||
PowerPC::SingleStep();
|
PowerPC::SingleStep();
|
||||||
|
|
||||||
//4: update disasm dialog
|
//4: update disasm dialog
|
||||||
if (m_SyncEvent) {
|
if (m_SyncEvent) {
|
||||||
m_SyncEvent->Set();
|
m_SyncEvent->Set();
|
||||||
m_SyncEvent = 0;
|
m_SyncEvent = 0;
|
||||||
}
|
}
|
||||||
Host_UpdateDisasmDialog();
|
Host_UpdateDisasmDialog();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPU_POWERDOWN:
|
case CPU_POWERDOWN:
|
||||||
//1: Exit loop!!
|
//1: Exit loop!!
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPU::Stop()
|
void CCPU::Stop()
|
||||||
{
|
{
|
||||||
PowerPC::Stop();
|
PowerPC::Stop();
|
||||||
m_StepEvent.Set();
|
m_StepEvent.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCPU::IsStepping()
|
bool CCPU::IsStepping()
|
||||||
{
|
{
|
||||||
return PowerPC::state == CPU_STEPPING;
|
return PowerPC::state == CPU_STEPPING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPU::Reset()
|
void CCPU::Reset()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPU::StepOpcode(Common::Event *event)
|
void CCPU::StepOpcode(Common::Event *event)
|
||||||
{
|
{
|
||||||
m_StepEvent.Set();
|
m_StepEvent.Set();
|
||||||
if (PowerPC::state == CPU_STEPPING)
|
if (PowerPC::state == CPU_STEPPING)
|
||||||
{
|
{
|
||||||
m_SyncEvent = event;
|
m_SyncEvent = event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPU::EnableStepping(const bool _bStepping)
|
void CCPU::EnableStepping(const bool _bStepping)
|
||||||
{
|
{
|
||||||
if (_bStepping)
|
if (_bStepping)
|
||||||
{
|
{
|
||||||
PowerPC::Pause();
|
PowerPC::Pause();
|
||||||
// TODO(ector): why a sleep?
|
// TODO(ector): why a sleep?
|
||||||
Host_SetDebugMode(true);
|
Host_SetDebugMode(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Host_SetDebugMode(false);
|
Host_SetDebugMode(false);
|
||||||
PowerPC::Start();
|
PowerPC::Start();
|
||||||
m_StepEvent.Set();
|
m_StepEvent.Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPU::SingleStep()
|
void CCPU::SingleStep()
|
||||||
{
|
{
|
||||||
switch (PowerPC::state)
|
switch (PowerPC::state)
|
||||||
{
|
{
|
||||||
case CPU_RUNNING:
|
case CPU_RUNNING:
|
||||||
//1: enter a fast runloop
|
//1: enter a fast runloop
|
||||||
PowerPC::RunLoop();
|
PowerPC::RunLoop();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPU_RUNNINGDEBUG:
|
case CPU_RUNNINGDEBUG:
|
||||||
//1: check for cpucompare
|
//1: check for cpucompare
|
||||||
if (CPUCompare::IsEnabled() && g_Branch)
|
if (CPUCompare::IsEnabled() && g_Branch)
|
||||||
{
|
{
|
||||||
g_Branch = false;
|
g_Branch = false;
|
||||||
CPUCompare::Sync();
|
CPUCompare::Sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
//2: check for breakpoint
|
//2: check for breakpoint
|
||||||
if (CBreakPoints::IsAddressBreakPoint(PC))
|
if (CBreakPoints::IsAddressBreakPoint(PC))
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "Hit Breakpoint - %08x", PC);
|
LOG(GEKKO, "Hit Breakpoint - %08x", PC);
|
||||||
EnableStepping(true);
|
EnableStepping(true);
|
||||||
if (CBreakPoints::IsTempBreakPoint(PC))
|
if (CBreakPoints::IsTempBreakPoint(PC))
|
||||||
CBreakPoints::RemoveBreakPoint(PC);
|
CBreakPoints::RemoveBreakPoint(PC);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Core::g_CoreStartupParameter.bUseJIT && CBreakPoints::GetBreakCount() == PowerPC::ppcState.DebugCount)
|
if (!Core::g_CoreStartupParameter.bUseJIT && CBreakPoints::GetBreakCount() == PowerPC::ppcState.DebugCount)
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "Hit DebugCount breakpoint - %i", PowerPC::ppcState.DebugCount);
|
LOG(GEKKO, "Hit DebugCount breakpoint - %i", PowerPC::ppcState.DebugCount);
|
||||||
EnableStepping(true);
|
EnableStepping(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//3: do a step
|
//3: do a step
|
||||||
PowerPC::SingleStep();
|
PowerPC::SingleStep();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPU_STEPPING:
|
case CPU_STEPPING:
|
||||||
//1: wait for step command..
|
//1: wait for step command..
|
||||||
m_StepEvent.Wait();
|
m_StepEvent.Wait();
|
||||||
|
|
||||||
//2: check for cpu compare
|
//2: check for cpu compare
|
||||||
if (CPUCompare::IsEnabled() && g_Branch)
|
if (CPUCompare::IsEnabled() && g_Branch)
|
||||||
{
|
{
|
||||||
g_Branch = false;
|
g_Branch = false;
|
||||||
CPUCompare::Sync();
|
CPUCompare::Sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
//3: do a step
|
//3: do a step
|
||||||
PowerPC::SingleStep();
|
PowerPC::SingleStep();
|
||||||
|
|
||||||
//4: update disasm dialog
|
//4: update disasm dialog
|
||||||
if (m_SyncEvent) {
|
if (m_SyncEvent) {
|
||||||
m_SyncEvent->Set();
|
m_SyncEvent->Set();
|
||||||
m_SyncEvent = 0;
|
m_SyncEvent = 0;
|
||||||
}
|
}
|
||||||
Host_UpdateDisasmDialog();
|
Host_UpdateDisasmDialog();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPU_POWERDOWN:
|
case CPU_POWERDOWN:
|
||||||
//1: Exit loop!!
|
//1: Exit loop!!
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPU::Break()
|
void CCPU::Break()
|
||||||
{
|
{
|
||||||
EnableStepping(true);
|
EnableStepping(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,246 +1,246 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
|
|
||||||
#include "CPUCompare.h"
|
#include "CPUCompare.h"
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "CommandProcessor.h"
|
#include "CommandProcessor.h"
|
||||||
|
|
||||||
|
|
||||||
#include "../Host.h"
|
#include "../Host.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
namespace CPUCompare
|
namespace CPUCompare
|
||||||
{
|
{
|
||||||
|
|
||||||
HANDLE m_hPipe;
|
HANDLE m_hPipe;
|
||||||
bool m_bIsServer;
|
bool m_bIsServer;
|
||||||
bool m_bEnabled;
|
bool m_bEnabled;
|
||||||
u32 m_BlockStart;
|
u32 m_BlockStart;
|
||||||
|
|
||||||
#define PIPENAME "\\\\.\\pipe\\cpucompare"
|
#define PIPENAME "\\\\.\\pipe\\cpucompare"
|
||||||
|
|
||||||
|
|
||||||
int stateSize = 32*4 + 32*16 + 6*4;
|
int stateSize = 32*4 + 32*16 + 6*4;
|
||||||
|
|
||||||
|
|
||||||
void SetBlockStart(u32 addr)
|
void SetBlockStart(u32 addr)
|
||||||
{
|
{
|
||||||
m_BlockStart = addr;
|
m_BlockStart = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartServer()
|
void StartServer()
|
||||||
{
|
{
|
||||||
_assert_msg_(GEKKO, Core::GetStartupParameter().bUseDualCore != true, "Don't use multithreading together with CPU-compare.");
|
_assert_msg_(GEKKO, Core::GetStartupParameter().bUseDualCore != true, "Don't use multithreading together with CPU-compare.");
|
||||||
|
|
||||||
if (m_bEnabled)
|
if (m_bEnabled)
|
||||||
return;
|
return;
|
||||||
//TODO: error checking
|
//TODO: error checking
|
||||||
m_hPipe = CreateNamedPipe(
|
m_hPipe = CreateNamedPipe(
|
||||||
PIPENAME,
|
PIPENAME,
|
||||||
PIPE_ACCESS_OUTBOUND,
|
PIPE_ACCESS_OUTBOUND,
|
||||||
PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
|
PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
|
||||||
1, //maxinst
|
1, //maxinst
|
||||||
0x1000, //outbufsize
|
0x1000, //outbufsize
|
||||||
0x1000, //inbufsize
|
0x1000, //inbufsize
|
||||||
INFINITE, //timeout
|
INFINITE, //timeout
|
||||||
0);
|
0);
|
||||||
_assert_msg_(GEKKO, m_hPipe != INVALID_HANDLE_VALUE, "Failed to create pipe.");
|
_assert_msg_(GEKKO, m_hPipe != INVALID_HANDLE_VALUE, "Failed to create pipe.");
|
||||||
//_assert_msg_(GEKKO, 0, "Pipe %s created.", PIPENAME);
|
//_assert_msg_(GEKKO, 0, "Pipe %s created.", PIPENAME);
|
||||||
|
|
||||||
m_bIsServer = true;
|
m_bIsServer = true;
|
||||||
m_bEnabled = true;
|
m_bEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectAsClient()
|
void ConnectAsClient()
|
||||||
{
|
{
|
||||||
_assert_msg_(GEKKO, Core::GetStartupParameter().bUseDualCore != true, "Don't use multithreading together with CPU-compare.");
|
_assert_msg_(GEKKO, Core::GetStartupParameter().bUseDualCore != true, "Don't use multithreading together with CPU-compare.");
|
||||||
|
|
||||||
if (m_bEnabled)
|
if (m_bEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//TODO: error checking
|
//TODO: error checking
|
||||||
m_hPipe = CreateFile(
|
m_hPipe = CreateFile(
|
||||||
PIPENAME,
|
PIPENAME,
|
||||||
GENERIC_READ,
|
GENERIC_READ,
|
||||||
0, //share
|
0, //share
|
||||||
NULL,
|
NULL,
|
||||||
OPEN_EXISTING,
|
OPEN_EXISTING,
|
||||||
0,
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
_assert_msg_(GEKKO, m_hPipe != INVALID_HANDLE_VALUE, "Failed to connect to pipe. %08x (2 = file not found)", GetLastError());
|
_assert_msg_(GEKKO, m_hPipe != INVALID_HANDLE_VALUE, "Failed to connect to pipe. %08x (2 = file not found)", GetLastError());
|
||||||
|
|
||||||
m_bEnabled = true;
|
m_bEnabled = true;
|
||||||
m_bIsServer = false;
|
m_bIsServer = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stop()
|
void Stop()
|
||||||
{
|
{
|
||||||
if (m_bEnabled)
|
if (m_bEnabled)
|
||||||
{
|
{
|
||||||
if (m_bIsServer)
|
if (m_bIsServer)
|
||||||
{
|
{
|
||||||
DisconnectNamedPipe(m_hPipe);
|
DisconnectNamedPipe(m_hPipe);
|
||||||
CloseHandle(m_hPipe);
|
CloseHandle(m_hPipe);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CloseHandle(m_hPipe); //both for server and client i guess
|
CloseHandle(m_hPipe); //both for server and client i guess
|
||||||
}
|
}
|
||||||
m_bEnabled=false;
|
m_bEnabled=false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Sync()
|
int Sync()
|
||||||
{
|
{
|
||||||
_assert_msg_(GEKKO,0,"Sync - PC = %08x", PC);
|
_assert_msg_(GEKKO,0,"Sync - PC = %08x", PC);
|
||||||
|
|
||||||
PowerPC::PowerPCState state;
|
PowerPC::PowerPCState state;
|
||||||
if (!m_bEnabled)
|
if (!m_bEnabled)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (m_bIsServer) // This should be interpreter
|
if (m_bIsServer) // This should be interpreter
|
||||||
{
|
{
|
||||||
//write cpu state to m_hPipe
|
//write cpu state to m_hPipe
|
||||||
HRESULT result;
|
HRESULT result;
|
||||||
u32 written;
|
u32 written;
|
||||||
// LogManager::Redraw();
|
// LogManager::Redraw();
|
||||||
result = WriteFile(m_hPipe, &PowerPC::ppcState, stateSize, (LPDWORD)&written,FALSE);
|
result = WriteFile(m_hPipe, &PowerPC::ppcState, stateSize, (LPDWORD)&written,FALSE);
|
||||||
//_assert_msg_(GEKKO, 0, "Server Wrote!");
|
//_assert_msg_(GEKKO, 0, "Server Wrote!");
|
||||||
if (FAILED(result))
|
if (FAILED(result))
|
||||||
{
|
{
|
||||||
_assert_msg_(GEKKO,0,"Failed to write cpu state to named pipe");
|
_assert_msg_(GEKKO,0,"Failed to write cpu state to named pipe");
|
||||||
Stop();
|
Stop();
|
||||||
}
|
}
|
||||||
// LogManager::Redraw();
|
// LogManager::Redraw();
|
||||||
}
|
}
|
||||||
else // This should be JIT
|
else // This should be JIT
|
||||||
{
|
{
|
||||||
u32 read;
|
u32 read;
|
||||||
memset(&state,0xcc,stateSize);
|
memset(&state,0xcc,stateSize);
|
||||||
BOOL res = ReadFile(m_hPipe, &state, stateSize, (LPDWORD)&read, FALSE);
|
BOOL res = ReadFile(m_hPipe, &state, stateSize, (LPDWORD)&read, FALSE);
|
||||||
//_assert_msg_(GEKKO, 0, "Client got data!");
|
//_assert_msg_(GEKKO, 0, "Client got data!");
|
||||||
|
|
||||||
//read cpu state to m_hPipe and compare
|
//read cpu state to m_hPipe and compare
|
||||||
//if any errors, print report
|
//if any errors, print report
|
||||||
if (!res || read != stateSize)
|
if (!res || read != stateSize)
|
||||||
{
|
{
|
||||||
_assert_msg_(GEKKO,0,"Failed to read cpu state from named pipe");
|
_assert_msg_(GEKKO,0,"Failed to read cpu state from named pipe");
|
||||||
Stop();
|
Stop();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool difference = false;
|
bool difference = false;
|
||||||
for (int i=0; i<32; i++)
|
for (int i=0; i<32; i++)
|
||||||
{
|
{
|
||||||
if (PowerPC::ppcState.gpr[i] != state.gpr[i])
|
if (PowerPC::ppcState.gpr[i] != state.gpr[i])
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "DIFFERENCE - r%i (local %08x, remote %08x)", i, PowerPC::ppcState.gpr[i], state.gpr[i]);
|
LOG(GEKKO, "DIFFERENCE - r%i (local %08x, remote %08x)", i, PowerPC::ppcState.gpr[i], state.gpr[i]);
|
||||||
difference = true;
|
difference = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<32; i++)
|
for (int i=0; i<32; i++)
|
||||||
{
|
{
|
||||||
for (int j=0; j<2; j++)
|
for (int j=0; j<2; j++)
|
||||||
{
|
{
|
||||||
if (PowerPC::ppcState.ps[i][j] != state.ps[i][j])
|
if (PowerPC::ppcState.ps[i][j] != state.ps[i][j])
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "DIFFERENCE - ps%i_%i (local %f, remote %f)", i, j, PowerPC::ppcState.ps[i][j], state.ps[i][j]);
|
LOG(GEKKO, "DIFFERENCE - ps%i_%i (local %f, remote %f)", i, j, PowerPC::ppcState.ps[i][j], state.ps[i][j]);
|
||||||
difference = true;
|
difference = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (PowerPC::ppcState.cr != state.cr)
|
if (PowerPC::ppcState.cr != state.cr)
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "DIFFERENCE - CR (local %08x, remote %08x)", PowerPC::ppcState.cr, state.cr);
|
LOG(GEKKO, "DIFFERENCE - CR (local %08x, remote %08x)", PowerPC::ppcState.cr, state.cr);
|
||||||
difference = true;
|
difference = true;
|
||||||
}
|
}
|
||||||
if (PowerPC::ppcState.pc != state.pc)
|
if (PowerPC::ppcState.pc != state.pc)
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "DIFFERENCE - PC (local %08x, remote %08x)", PowerPC::ppcState.pc, state.pc);
|
LOG(GEKKO, "DIFFERENCE - PC (local %08x, remote %08x)", PowerPC::ppcState.pc, state.pc);
|
||||||
difference = true;
|
difference = true;
|
||||||
}
|
}
|
||||||
//if (PowerPC::ppcState.npc != state.npc)
|
//if (PowerPC::ppcState.npc != state.npc)
|
||||||
///{
|
///{
|
||||||
// LOG(GEKKO, "DIFFERENCE - NPC (local %08x, remote %08x)", PowerPC::ppcState.npc, state.npc);
|
// LOG(GEKKO, "DIFFERENCE - NPC (local %08x, remote %08x)", PowerPC::ppcState.npc, state.npc);
|
||||||
// difference = true;
|
// difference = true;
|
||||||
//}
|
//}
|
||||||
if (PowerPC::ppcState.msr != state.msr)
|
if (PowerPC::ppcState.msr != state.msr)
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "DIFFERENCE - MSR (local %08x, remote %08x)", PowerPC::ppcState.msr, state.msr);
|
LOG(GEKKO, "DIFFERENCE - MSR (local %08x, remote %08x)", PowerPC::ppcState.msr, state.msr);
|
||||||
difference = true;
|
difference = true;
|
||||||
}
|
}
|
||||||
if (PowerPC::ppcState.fpscr != state.fpscr)
|
if (PowerPC::ppcState.fpscr != state.fpscr)
|
||||||
{
|
{
|
||||||
LOG(GEKKO, "DIFFERENCE - FPSCR (local %08x, remote %08x)", PowerPC::ppcState.fpscr, state.fpscr);
|
LOG(GEKKO, "DIFFERENCE - FPSCR (local %08x, remote %08x)", PowerPC::ppcState.fpscr, state.fpscr);
|
||||||
difference = true;
|
difference = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (difference)
|
if (difference)
|
||||||
{
|
{
|
||||||
Host_UpdateLogDisplay();
|
Host_UpdateLogDisplay();
|
||||||
//Also show drec compare window here
|
//Also show drec compare window here
|
||||||
//CDynaViewDlg::Show(true);
|
//CDynaViewDlg::Show(true);
|
||||||
//CDynaViewDlg::ViewAddr(m_BlockStart);
|
//CDynaViewDlg::ViewAddr(m_BlockStart);
|
||||||
//CDynaViewDlg::Show(true);
|
//CDynaViewDlg::Show(true);
|
||||||
//Sleep(INFINITE);
|
//Sleep(INFINITE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
//LOG(GEKKO, "No difference!");
|
//LOG(GEKKO, "No difference!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsEnabled()
|
bool IsEnabled()
|
||||||
{
|
{
|
||||||
return m_bEnabled;
|
return m_bEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsServer()
|
bool IsServer()
|
||||||
{
|
{
|
||||||
return m_bIsServer;
|
return m_bIsServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
namespace CPUCompare
|
namespace CPUCompare
|
||||||
{
|
{
|
||||||
void StartServer() { }
|
void StartServer() { }
|
||||||
void ConnectAsClient() { }
|
void ConnectAsClient() { }
|
||||||
void Stop() { }
|
void Stop() { }
|
||||||
int Sync() { return 0; }
|
int Sync() { return 0; }
|
||||||
bool IsEnabled() { return false; }
|
bool IsEnabled() { return false; }
|
||||||
bool IsServer() { return false; }
|
bool IsServer() { return false; }
|
||||||
}
|
}
|
||||||
// #error Provide a CPUCompare implementation or dummy it out, please
|
// #error Provide a CPUCompare implementation or dummy it out, please
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,116 +1,116 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
|
|
||||||
#include "PeripheralInterface.h"
|
#include "PeripheralInterface.h"
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
|
|
||||||
#include "EXI_Device.h"
|
#include "EXI_Device.h"
|
||||||
#include "EXI_Channel.h"
|
#include "EXI_Channel.h"
|
||||||
|
|
||||||
namespace ExpansionInterface
|
namespace ExpansionInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
NUM_CHANNELS = 3
|
NUM_CHANNELS = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
CEXIChannel *g_Channels;
|
CEXIChannel *g_Channels;
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
g_Channels = new CEXIChannel[3];
|
g_Channels = new CEXIChannel[3];
|
||||||
g_Channels[0].m_ChannelId = 0;
|
g_Channels[0].m_ChannelId = 0;
|
||||||
g_Channels[1].m_ChannelId = 1;
|
g_Channels[1].m_ChannelId = 1;
|
||||||
g_Channels[2].m_ChannelId = 2;
|
g_Channels[2].m_ChannelId = 2;
|
||||||
|
|
||||||
g_Channels[0].AddDevice(EXIDEVICE_MEMORYCARD_A, 0);
|
g_Channels[0].AddDevice(EXIDEVICE_MEMORYCARD_A, 0);
|
||||||
g_Channels[0].AddDevice(EXIDEVICE_IPL, 1);
|
g_Channels[0].AddDevice(EXIDEVICE_IPL, 1);
|
||||||
g_Channels[1].AddDevice(EXIDEVICE_MEMORYCARD_B, 0);
|
g_Channels[1].AddDevice(EXIDEVICE_MEMORYCARD_B, 0);
|
||||||
#if 0
|
#if 0
|
||||||
g_Channels[0].AddDevice(EXIDEVICE_ETH, 2);
|
g_Channels[0].AddDevice(EXIDEVICE_ETH, 2);
|
||||||
#endif
|
#endif
|
||||||
//g_Channels[1].AddDevice(EXIDEVICE_MIC, 0);
|
//g_Channels[1].AddDevice(EXIDEVICE_MIC, 0);
|
||||||
g_Channels[2].AddDevice(EXIDEVICE_AD16, 0);
|
g_Channels[2].AddDevice(EXIDEVICE_AD16, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
delete [] g_Channels;
|
delete [] g_Channels;
|
||||||
g_Channels = 0;
|
g_Channels = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
// TODO: descend all the devices recursively.
|
// TODO: descend all the devices recursively.
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
g_Channels[0].Update();
|
g_Channels[0].Update();
|
||||||
g_Channels[1].Update();
|
g_Channels[1].Update();
|
||||||
g_Channels[2].Update();
|
g_Channels[2].Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Read32(u32& _uReturnValue, const u32 _iAddress)
|
void Read32(u32& _uReturnValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
unsigned int iAddr = _iAddress & 0x3FF;
|
unsigned int iAddr = _iAddress & 0x3FF;
|
||||||
unsigned int iRegister = (iAddr >> 2) % 5;
|
unsigned int iRegister = (iAddr >> 2) % 5;
|
||||||
unsigned int iChannel = (iAddr >> 2) / 5;
|
unsigned int iChannel = (iAddr >> 2) / 5;
|
||||||
|
|
||||||
_dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS);
|
_dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS);
|
||||||
|
|
||||||
if (iChannel < NUM_CHANNELS)
|
if (iChannel < NUM_CHANNELS)
|
||||||
{
|
{
|
||||||
g_Channels[iChannel].Read32(_uReturnValue, iRegister);
|
g_Channels[iChannel].Read32(_uReturnValue, iRegister);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_uReturnValue = 0;
|
_uReturnValue = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write32(const u32 _iValue, const u32 _iAddress)
|
void Write32(const u32 _iValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
int iAddr = _iAddress & 0x3FF;
|
int iAddr = _iAddress & 0x3FF;
|
||||||
int iRegister = (iAddr >> 2) % 5;
|
int iRegister = (iAddr >> 2) % 5;
|
||||||
int iChannel = (iAddr >> 2) / 5;
|
int iChannel = (iAddr >> 2) / 5;
|
||||||
|
|
||||||
_dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS)
|
_dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS)
|
||||||
|
|
||||||
if (iChannel < NUM_CHANNELS)
|
if (iChannel < NUM_CHANNELS)
|
||||||
g_Channels[iChannel].Write32(_iValue, iRegister);
|
g_Channels[iChannel].Write32(_iValue, iRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateInterrupts()
|
void UpdateInterrupts()
|
||||||
{
|
{
|
||||||
for(int i=0; i<NUM_CHANNELS; i++)
|
for(int i=0; i<NUM_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
if(g_Channels[i].IsCausingInterrupt())
|
if(g_Channels[i].IsCausingInterrupt())
|
||||||
{
|
{
|
||||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_EXI, true);
|
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_EXI, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_EXI, false);
|
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_EXI, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace ExpansionInterface
|
} // end of namespace ExpansionInterface
|
||||||
|
|
|
@ -1,284 +1,284 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "EXI_Channel.h"
|
#include "EXI_Channel.h"
|
||||||
#include "EXI.h"
|
#include "EXI.h"
|
||||||
|
|
||||||
#include "PeripheralInterface.h"
|
#include "PeripheralInterface.h"
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
|
|
||||||
CEXIChannel::CEXIChannel() :
|
CEXIChannel::CEXIChannel() :
|
||||||
m_DMAMemoryAddress(0),
|
m_DMAMemoryAddress(0),
|
||||||
m_DMALength(0),
|
m_DMALength(0),
|
||||||
m_ImmData(0),
|
m_ImmData(0),
|
||||||
m_ChannelId(-1)
|
m_ChannelId(-1)
|
||||||
{
|
{
|
||||||
m_Control.hex = 0;
|
m_Control.hex = 0;
|
||||||
m_Status.hex = 0;
|
m_Status.hex = 0;
|
||||||
|
|
||||||
m_Status.CHIP_SELECT = 1;
|
m_Status.CHIP_SELECT = 1;
|
||||||
|
|
||||||
for (int i = 0; i < NUM_DEVICES; i++)
|
for (int i = 0; i < NUM_DEVICES; i++)
|
||||||
{
|
{
|
||||||
m_pDevices[i] = EXIDevice_Create(EXIDEVICE_DUMMY);
|
m_pDevices[i] = EXIDevice_Create(EXIDEVICE_DUMMY);
|
||||||
_dbg_assert_(EXPANSIONINTERFACE, m_pDevices[i] != NULL);
|
_dbg_assert_(EXPANSIONINTERFACE, m_pDevices[i] != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Status.TCINTMASK = 1;
|
m_Status.TCINTMASK = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
CEXIChannel::~CEXIChannel()
|
CEXIChannel::~CEXIChannel()
|
||||||
{
|
{
|
||||||
RemoveDevices();
|
RemoveDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIChannel::RemoveDevices()
|
void CEXIChannel::RemoveDevices()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUM_DEVICES; i++)
|
for (int i = 0; i < NUM_DEVICES; i++)
|
||||||
{
|
{
|
||||||
if (m_pDevices[i] != NULL)
|
if (m_pDevices[i] != NULL)
|
||||||
{
|
{
|
||||||
delete m_pDevices[i];
|
delete m_pDevices[i];
|
||||||
m_pDevices[i] = NULL;
|
m_pDevices[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIChannel::AddDevice(const TEXIDevices _device, const unsigned int _iSlot)
|
void CEXIChannel::AddDevice(const TEXIDevices _device, const unsigned int _iSlot)
|
||||||
{
|
{
|
||||||
_dbg_assert_(EXPANSIONINTERFACE, _iSlot < NUM_DEVICES);
|
_dbg_assert_(EXPANSIONINTERFACE, _iSlot < NUM_DEVICES);
|
||||||
|
|
||||||
// delete the old device
|
// delete the old device
|
||||||
if (m_pDevices[_iSlot] != NULL)
|
if (m_pDevices[_iSlot] != NULL)
|
||||||
{
|
{
|
||||||
delete m_pDevices[_iSlot];
|
delete m_pDevices[_iSlot];
|
||||||
m_pDevices[_iSlot] = NULL;
|
m_pDevices[_iSlot] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the new one
|
// create the new one
|
||||||
m_pDevices[_iSlot] = EXIDevice_Create(_device);
|
m_pDevices[_iSlot] = EXIDevice_Create(_device);
|
||||||
_dbg_assert_(EXPANSIONINTERFACE, m_pDevices[_iSlot] != NULL);
|
_dbg_assert_(EXPANSIONINTERFACE, m_pDevices[_iSlot] != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIChannel::UpdateInterrupts()
|
void CEXIChannel::UpdateInterrupts()
|
||||||
{
|
{
|
||||||
ExpansionInterface::UpdateInterrupts();
|
ExpansionInterface::UpdateInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CEXIChannel::IsCausingInterrupt()
|
bool CEXIChannel::IsCausingInterrupt()
|
||||||
{
|
{
|
||||||
if (m_ChannelId != 2) /* Channels 0 and 1: Memcard slot (device 0) produces interrupt */
|
if (m_ChannelId != 2) /* Channels 0 and 1: Memcard slot (device 0) produces interrupt */
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUM_DEVICES; i++)
|
for (int i = 0; i < NUM_DEVICES; i++)
|
||||||
if (m_pDevices[i]->IsInterruptSet())
|
if (m_pDevices[i]->IsInterruptSet())
|
||||||
m_Status.EXIINT = 1;
|
m_Status.EXIINT = 1;
|
||||||
}
|
}
|
||||||
else /* Channel 2: In fact, Channel 0, Device 2 (Serial A) produces interrupt */
|
else /* Channel 2: In fact, Channel 0, Device 2 (Serial A) produces interrupt */
|
||||||
{
|
{
|
||||||
// WTF? this[-2]??? EVIL HACK
|
// WTF? this[-2]??? EVIL HACK
|
||||||
if (this[-2].m_pDevices[2]->IsInterruptSet())
|
if (this[-2].m_pDevices[2]->IsInterruptSet())
|
||||||
m_Status.EXIINT = 1;
|
m_Status.EXIINT = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_Status.EXIINT & m_Status.EXIINTMASK) ||
|
if ((m_Status.EXIINT & m_Status.EXIINTMASK) ||
|
||||||
(m_Status.TCINT & m_Status.TCINTMASK) ||
|
(m_Status.TCINT & m_Status.TCINTMASK) ||
|
||||||
(m_Status.EXTINT & m_Status.EXTINTMASK))
|
(m_Status.EXTINT & m_Status.EXTINTMASK))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEXIDevice* CEXIChannel::GetDevice(u8 _CHIP_SELECT)
|
IEXIDevice* CEXIChannel::GetDevice(u8 _CHIP_SELECT)
|
||||||
{
|
{
|
||||||
switch(_CHIP_SELECT)
|
switch(_CHIP_SELECT)
|
||||||
{
|
{
|
||||||
case 1: return m_pDevices[0];
|
case 1: return m_pDevices[0];
|
||||||
case 2: return m_pDevices[1];
|
case 2: return m_pDevices[1];
|
||||||
case 4: return m_pDevices[2];
|
case 4: return m_pDevices[2];
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIChannel::Update()
|
void CEXIChannel::Update()
|
||||||
{
|
{
|
||||||
// start the transfer
|
// start the transfer
|
||||||
for (int i = 0; i < NUM_DEVICES; i++)
|
for (int i = 0; i < NUM_DEVICES; i++)
|
||||||
{
|
{
|
||||||
m_pDevices[i]->Update();
|
m_pDevices[i]->Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
|
void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
|
||||||
{
|
{
|
||||||
LOGV(EXPANSIONINTERFACE, 3, "ExtensionInterface(R): channel: %i reg: %i", m_ChannelId, _iRegister);
|
LOGV(EXPANSIONINTERFACE, 3, "ExtensionInterface(R): channel: %i reg: %i", m_ChannelId, _iRegister);
|
||||||
|
|
||||||
switch (_iRegister)
|
switch (_iRegister)
|
||||||
{
|
{
|
||||||
case EXI_STATUS:
|
case EXI_STATUS:
|
||||||
{
|
{
|
||||||
// check if a device is present
|
// check if a device is present
|
||||||
for (int i = 0; i < NUM_DEVICES; i++)
|
for (int i = 0; i < NUM_DEVICES; i++)
|
||||||
{
|
{
|
||||||
if (m_pDevices[i]->IsPresent())
|
if (m_pDevices[i]->IsPresent())
|
||||||
{
|
{
|
||||||
m_Status.EXT = 1;
|
m_Status.EXT = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_uReturnValue = m_Status.hex;
|
_uReturnValue = m_Status.hex;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EXI_DMAADDR:
|
case EXI_DMAADDR:
|
||||||
_uReturnValue = m_DMAMemoryAddress;
|
_uReturnValue = m_DMAMemoryAddress;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXI_DMALENGTH:
|
case EXI_DMALENGTH:
|
||||||
_uReturnValue = m_DMALength;
|
_uReturnValue = m_DMALength;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXI_DMACONTROL:
|
case EXI_DMACONTROL:
|
||||||
_uReturnValue = m_Control.hex;
|
_uReturnValue = m_Control.hex;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXI_IMMDATA:
|
case EXI_IMMDATA:
|
||||||
_uReturnValue = m_ImmData;
|
_uReturnValue = m_ImmData;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_dbg_assert_(EXPANSIONINTERFACE, 0);
|
_dbg_assert_(EXPANSIONINTERFACE, 0);
|
||||||
_uReturnValue = 0xDEADBEEF;
|
_uReturnValue = 0xDEADBEEF;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
||||||
{
|
{
|
||||||
LOGV(EXPANSIONINTERFACE, 2, "ExtensionInterface(W): 0x%08x channel: %i reg: %i", _iValue, m_ChannelId, _iRegister);
|
LOGV(EXPANSIONINTERFACE, 2, "ExtensionInterface(W): 0x%08x channel: %i reg: %i", _iValue, m_ChannelId, _iRegister);
|
||||||
|
|
||||||
switch (_iRegister)
|
switch (_iRegister)
|
||||||
{
|
{
|
||||||
case EXI_STATUS:
|
case EXI_STATUS:
|
||||||
{
|
{
|
||||||
UEXI_STATUS newStatus(_iValue);
|
UEXI_STATUS newStatus(_iValue);
|
||||||
|
|
||||||
// static
|
// static
|
||||||
m_Status.EXIINTMASK = newStatus.EXIINTMASK;
|
m_Status.EXIINTMASK = newStatus.EXIINTMASK;
|
||||||
m_Status.TCINTMASK = newStatus.TCINTMASK;
|
m_Status.TCINTMASK = newStatus.TCINTMASK;
|
||||||
m_Status.EXTINTMASK = newStatus.EXTINTMASK;
|
m_Status.EXTINTMASK = newStatus.EXTINTMASK;
|
||||||
m_Status.CLK = newStatus.CLK;
|
m_Status.CLK = newStatus.CLK;
|
||||||
m_Status.ROMDIS = newStatus.ROMDIS;
|
m_Status.ROMDIS = newStatus.ROMDIS;
|
||||||
|
|
||||||
// Device
|
// Device
|
||||||
if (m_Status.CHIP_SELECT != newStatus.CHIP_SELECT)
|
if (m_Status.CHIP_SELECT != newStatus.CHIP_SELECT)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUM_DEVICES; i++)
|
for (int i = 0; i < NUM_DEVICES; i++)
|
||||||
{
|
{
|
||||||
u8 dwDeviceMask = 1 << i;
|
u8 dwDeviceMask = 1 << i;
|
||||||
IEXIDevice* pDevice = GetDevice(dwDeviceMask);
|
IEXIDevice* pDevice = GetDevice(dwDeviceMask);
|
||||||
if (pDevice != NULL)
|
if (pDevice != NULL)
|
||||||
{
|
{
|
||||||
if (((newStatus.CHIP_SELECT & dwDeviceMask) == dwDeviceMask) &&
|
if (((newStatus.CHIP_SELECT & dwDeviceMask) == dwDeviceMask) &&
|
||||||
((m_Status.CHIP_SELECT & dwDeviceMask) == 0))
|
((m_Status.CHIP_SELECT & dwDeviceMask) == 0))
|
||||||
// device gets activated
|
// device gets activated
|
||||||
pDevice->SetCS(1);
|
pDevice->SetCS(1);
|
||||||
|
|
||||||
if (((newStatus.CHIP_SELECT & dwDeviceMask) == 0) &&
|
if (((newStatus.CHIP_SELECT & dwDeviceMask) == 0) &&
|
||||||
((m_Status.CHIP_SELECT & dwDeviceMask) == dwDeviceMask))
|
((m_Status.CHIP_SELECT & dwDeviceMask) == dwDeviceMask))
|
||||||
// device gets deactivated
|
// device gets deactivated
|
||||||
pDevice->SetCS(0);
|
pDevice->SetCS(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_Status.CHIP_SELECT = newStatus.CHIP_SELECT;
|
m_Status.CHIP_SELECT = newStatus.CHIP_SELECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// External Status
|
// External Status
|
||||||
IEXIDevice* pDevice = GetDevice(newStatus.CHIP_SELECT);
|
IEXIDevice* pDevice = GetDevice(newStatus.CHIP_SELECT);
|
||||||
if (pDevice != NULL)
|
if (pDevice != NULL)
|
||||||
m_Status.EXT = pDevice->IsPresent() ? 1 : 0;
|
m_Status.EXT = pDevice->IsPresent() ? 1 : 0;
|
||||||
else
|
else
|
||||||
m_Status.EXT = 0;
|
m_Status.EXT = 0;
|
||||||
|
|
||||||
// interrupt
|
// interrupt
|
||||||
if (newStatus.EXIINT) m_Status.EXIINT = 0;
|
if (newStatus.EXIINT) m_Status.EXIINT = 0;
|
||||||
if (newStatus.TCINT) m_Status.TCINT = 0;
|
if (newStatus.TCINT) m_Status.TCINT = 0;
|
||||||
if (newStatus.EXTINT) m_Status.EXTINT = 0;
|
if (newStatus.EXTINT) m_Status.EXTINT = 0;
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXI_DMAADDR:
|
case EXI_DMAADDR:
|
||||||
LOGV(EXPANSIONINTERFACE, 2, "EXI: Wrote DMABuf, chan %i", m_ChannelId);
|
LOGV(EXPANSIONINTERFACE, 2, "EXI: Wrote DMABuf, chan %i", m_ChannelId);
|
||||||
m_DMAMemoryAddress = _iValue;
|
m_DMAMemoryAddress = _iValue;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXI_DMALENGTH:
|
case EXI_DMALENGTH:
|
||||||
LOGV(EXPANSIONINTERFACE, 2, "EXI: Wrote DMASize, chan %i", m_ChannelId);
|
LOGV(EXPANSIONINTERFACE, 2, "EXI: Wrote DMASize, chan %i", m_ChannelId);
|
||||||
m_DMALength = _iValue;
|
m_DMALength = _iValue;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXI_DMACONTROL:
|
case EXI_DMACONTROL:
|
||||||
LOGV(EXPANSIONINTERFACE, 2, "EXI: Wrote DMAControl, chan %i", m_ChannelId);
|
LOGV(EXPANSIONINTERFACE, 2, "EXI: Wrote DMAControl, chan %i", m_ChannelId);
|
||||||
m_Control.hex = _iValue;
|
m_Control.hex = _iValue;
|
||||||
|
|
||||||
if (m_Control.TSTART)
|
if (m_Control.TSTART)
|
||||||
{
|
{
|
||||||
IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT);
|
IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT);
|
||||||
if (pDevice == NULL)
|
if (pDevice == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_Control.DMA == 0)
|
if (m_Control.DMA == 0)
|
||||||
{
|
{
|
||||||
// immediate data
|
// immediate data
|
||||||
switch (m_Control.RW)
|
switch (m_Control.RW)
|
||||||
{
|
{
|
||||||
case 0: m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1); break;
|
case 0: m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1); break;
|
||||||
case 1: pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1); break;
|
case 1: pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1); break;
|
||||||
default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI Imm: Unknown transfer type %i", m_Control.RW);
|
default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI Imm: Unknown transfer type %i", m_Control.RW);
|
||||||
}
|
}
|
||||||
m_Control.TSTART = 0;
|
m_Control.TSTART = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// DMA
|
// DMA
|
||||||
switch (m_Control.RW)
|
switch (m_Control.RW)
|
||||||
{
|
{
|
||||||
case 0: pDevice->DMARead (m_DMAMemoryAddress, m_DMALength); break;
|
case 0: pDevice->DMARead (m_DMAMemoryAddress, m_DMALength); break;
|
||||||
case 1: pDevice->DMAWrite(m_DMAMemoryAddress, m_DMALength); break;
|
case 1: pDevice->DMAWrite(m_DMAMemoryAddress, m_DMALength); break;
|
||||||
default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI DMA: Unknown transfer type %i", m_Control.RW);
|
default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI DMA: Unknown transfer type %i", m_Control.RW);
|
||||||
}
|
}
|
||||||
m_Control.TSTART = 0;
|
m_Control.TSTART = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!m_Control.TSTART) // completed !
|
if(!m_Control.TSTART) // completed !
|
||||||
{
|
{
|
||||||
m_Status.TCINT = 1;
|
m_Status.TCINT = 1;
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXI_IMMDATA:
|
case EXI_IMMDATA:
|
||||||
LOGV(EXPANSIONINTERFACE, 2, "EXI: Wrote IMMData, chan %i", m_ChannelId);
|
LOGV(EXPANSIONINTERFACE, 2, "EXI: Wrote IMMData, chan %i", m_ChannelId);
|
||||||
m_ImmData = _iValue;
|
m_ImmData = _iValue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,164 +1,164 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Memmap.h"
|
#include "Memmap.h"
|
||||||
|
|
||||||
#include "EXI_Device.h"
|
#include "EXI_Device.h"
|
||||||
#include "EXI_DeviceIPL.h"
|
#include "EXI_DeviceIPL.h"
|
||||||
#include "EXI_DeviceMemoryCard.h"
|
#include "EXI_DeviceMemoryCard.h"
|
||||||
#include "EXI_DeviceAD16.h"
|
#include "EXI_DeviceAD16.h"
|
||||||
#include "EXI_DeviceMic.h"
|
#include "EXI_DeviceMic.h"
|
||||||
#if 0
|
#if 0
|
||||||
#include "EXI_DeviceEthernet.h"
|
#include "EXI_DeviceEthernet.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// --- interface IEXIDevice ---
|
// --- interface IEXIDevice ---
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void IEXIDevice::ImmWrite(u32 _uData, u32 _uSize)
|
void IEXIDevice::ImmWrite(u32 _uData, u32 _uSize)
|
||||||
{
|
{
|
||||||
while (_uSize--)
|
while (_uSize--)
|
||||||
{
|
{
|
||||||
u8 uByte = _uData >> 24;
|
u8 uByte = _uData >> 24;
|
||||||
TransferByte(uByte);
|
TransferByte(uByte);
|
||||||
_uData <<= 8;
|
_uData <<= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 IEXIDevice::ImmRead(u32 _uSize)
|
u32 IEXIDevice::ImmRead(u32 _uSize)
|
||||||
{
|
{
|
||||||
u32 uResult = 0;
|
u32 uResult = 0;
|
||||||
u32 uPosition = 0;
|
u32 uPosition = 0;
|
||||||
while (_uSize--)
|
while (_uSize--)
|
||||||
{
|
{
|
||||||
u8 uByte = 0;
|
u8 uByte = 0;
|
||||||
TransferByte(uByte);
|
TransferByte(uByte);
|
||||||
uResult |= uByte << (24-(uPosition++ * 8));
|
uResult |= uByte << (24-(uPosition++ * 8));
|
||||||
}
|
}
|
||||||
return uResult;
|
return uResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEXIDevice::DMAWrite(u32 _uAddr, u32 _uSize)
|
void IEXIDevice::DMAWrite(u32 _uAddr, u32 _uSize)
|
||||||
{
|
{
|
||||||
// _dbg_assert_(EXPANSIONINTERFACE, 0);
|
// _dbg_assert_(EXPANSIONINTERFACE, 0);
|
||||||
while (_uSize--)
|
while (_uSize--)
|
||||||
{
|
{
|
||||||
u8 uByte = Memory::Read_U8(_uAddr++);
|
u8 uByte = Memory::Read_U8(_uAddr++);
|
||||||
TransferByte(uByte);
|
TransferByte(uByte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEXIDevice::DMARead(u32 _uAddr, u32 _uSize)
|
void IEXIDevice::DMARead(u32 _uAddr, u32 _uSize)
|
||||||
{
|
{
|
||||||
// _dbg_assert_(EXPANSIONINTERFACE, 0);
|
// _dbg_assert_(EXPANSIONINTERFACE, 0);
|
||||||
while (_uSize--)
|
while (_uSize--)
|
||||||
{
|
{
|
||||||
u8 uByte = 0;
|
u8 uByte = 0;
|
||||||
TransferByte(uByte);
|
TransferByte(uByte);
|
||||||
Memory::Write_U8(uByte, _uAddr++);
|
Memory::Write_U8(uByte, _uAddr++);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool IEXIDevice::IsPresent()
|
bool IEXIDevice::IsPresent()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEXIDevice::Update()
|
void IEXIDevice::Update()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IEXIDevice::IsInterruptSet()
|
bool IEXIDevice::IsInterruptSet()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEXIDevice::SetCS(int _iCS)
|
void IEXIDevice::SetCS(int _iCS)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// --- class CEXIDummy ---
|
// --- class CEXIDummy ---
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// just a dummy that logs reads and writes
|
// just a dummy that logs reads and writes
|
||||||
// to be used for EXI devices we haven't emulated
|
// to be used for EXI devices we haven't emulated
|
||||||
class CEXIDummy : public IEXIDevice
|
class CEXIDummy : public IEXIDevice
|
||||||
{
|
{
|
||||||
std::string m_strName;
|
std::string m_strName;
|
||||||
|
|
||||||
void TransferByte(u8& _byte) {}
|
void TransferByte(u8& _byte) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CEXIDummy(const std::string& _strName) :
|
CEXIDummy(const std::string& _strName) :
|
||||||
m_strName(_strName)
|
m_strName(_strName)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~CEXIDummy(){}
|
virtual ~CEXIDummy(){}
|
||||||
|
|
||||||
void ImmWrite(u32 data, u32 size){LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmWrite: %08x",m_strName.c_str(),data);}
|
void ImmWrite(u32 data, u32 size){LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmWrite: %08x",m_strName.c_str(),data);}
|
||||||
u32 ImmRead (u32 size) {LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead",m_strName.c_str()); return 0;}
|
u32 ImmRead (u32 size) {LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead",m_strName.c_str()); return 0;}
|
||||||
void DMAWrite(u32 addr, u32 size) {LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMAWrite: %08x bytes, from %08x to device",m_strName.c_str(),size,addr);}
|
void DMAWrite(u32 addr, u32 size) {LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMAWrite: %08x bytes, from %08x to device",m_strName.c_str(),size,addr);}
|
||||||
void DMARead (u32 addr, u32 size) {LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMARead: %08x bytes, from device to %08x",m_strName.c_str(),size,addr);}
|
void DMARead (u32 addr, u32 size) {LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMARead: %08x bytes, from device to %08x",m_strName.c_str(),size,addr);}
|
||||||
};
|
};
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// F A C T O R Y ////////////////////////////////////////////////////////////////////////////////////
|
// F A C T O R Y ////////////////////////////////////////////////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
|
IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
|
||||||
{
|
{
|
||||||
switch(_EXIDevice)
|
switch(_EXIDevice)
|
||||||
{
|
{
|
||||||
case EXIDEVICE_DUMMY:
|
case EXIDEVICE_DUMMY:
|
||||||
return new CEXIDummy("Dummy");
|
return new CEXIDummy("Dummy");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_MEMORYCARD_A:
|
case EXIDEVICE_MEMORYCARD_A:
|
||||||
return new CEXIMemoryCard("MemoryCardA", Core::GetStartupParameter().m_strMemoryCardA, 0);
|
return new CEXIMemoryCard("MemoryCardA", Core::GetStartupParameter().m_strMemoryCardA, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_MEMORYCARD_B:
|
case EXIDEVICE_MEMORYCARD_B:
|
||||||
return new CEXIMemoryCard("MemoryCardB", Core::GetStartupParameter().m_strMemoryCardB, 1);
|
return new CEXIMemoryCard("MemoryCardB", Core::GetStartupParameter().m_strMemoryCardB, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_IPL:
|
case EXIDEVICE_IPL:
|
||||||
return new CEXIIPL();
|
return new CEXIIPL();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_AD16:
|
case EXIDEVICE_AD16:
|
||||||
return new CEXIAD16();
|
return new CEXIAD16();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_MIC:
|
case EXIDEVICE_MIC:
|
||||||
return new CEXIMic(1);
|
return new CEXIMic(1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_ETH:
|
case EXIDEVICE_ETH:
|
||||||
#if 0
|
#if 0
|
||||||
return new CEXIETHERNET();
|
return new CEXIETHERNET();
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,92 +1,92 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
|
|
||||||
#include "EXI_Device.h"
|
#include "EXI_Device.h"
|
||||||
#include "EXI_DeviceAD16.h"
|
#include "EXI_DeviceAD16.h"
|
||||||
|
|
||||||
CEXIAD16::CEXIAD16() :
|
CEXIAD16::CEXIAD16() :
|
||||||
m_uPosition(0),
|
m_uPosition(0),
|
||||||
m_uCommand(0)
|
m_uCommand(0)
|
||||||
{
|
{
|
||||||
m_uAD16Register.U32 = 0x00;
|
m_uAD16Register.U32 = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIAD16::SetCS(int cs)
|
void CEXIAD16::SetCS(int cs)
|
||||||
{
|
{
|
||||||
if (cs)
|
if (cs)
|
||||||
m_uPosition = 0;
|
m_uPosition = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CEXIAD16::IsPresent()
|
bool CEXIAD16::IsPresent()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIAD16::TransferByte(u8& _byte)
|
void CEXIAD16::TransferByte(u8& _byte)
|
||||||
{
|
{
|
||||||
if (m_uPosition == 0)
|
if (m_uPosition == 0)
|
||||||
{
|
{
|
||||||
m_uCommand = _byte;
|
m_uCommand = _byte;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch(m_uCommand)
|
switch(m_uCommand)
|
||||||
{
|
{
|
||||||
case init:
|
case init:
|
||||||
{
|
{
|
||||||
m_uAD16Register.U32 = 0x04120000;
|
m_uAD16Register.U32 = 0x04120000;
|
||||||
switch(m_uPosition)
|
switch(m_uPosition)
|
||||||
{
|
{
|
||||||
case 1: _dbg_assert_(EXPANSIONINTERFACE, (_byte == 0x00)); break; // just skip
|
case 1: _dbg_assert_(EXPANSIONINTERFACE, (_byte == 0x00)); break; // just skip
|
||||||
case 2: _byte = m_uAD16Register.U8[0]; break;
|
case 2: _byte = m_uAD16Register.U8[0]; break;
|
||||||
case 3: _byte = m_uAD16Register.U8[1]; break;
|
case 3: _byte = m_uAD16Register.U8[1]; break;
|
||||||
case 4: _byte = m_uAD16Register.U8[2]; break;
|
case 4: _byte = m_uAD16Register.U8[2]; break;
|
||||||
case 5: _byte = m_uAD16Register.U8[3]; break;
|
case 5: _byte = m_uAD16Register.U8[3]; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case write:
|
case write:
|
||||||
{
|
{
|
||||||
switch(m_uPosition)
|
switch(m_uPosition)
|
||||||
{
|
{
|
||||||
case 1: m_uAD16Register.U8[0] = _byte; break;
|
case 1: m_uAD16Register.U8[0] = _byte; break;
|
||||||
case 2: m_uAD16Register.U8[1] = _byte; break;
|
case 2: m_uAD16Register.U8[1] = _byte; break;
|
||||||
case 3: m_uAD16Register.U8[2] = _byte; break;
|
case 3: m_uAD16Register.U8[2] = _byte; break;
|
||||||
case 4: m_uAD16Register.U8[3] = _byte; break;
|
case 4: m_uAD16Register.U8[3] = _byte; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case read:
|
case read:
|
||||||
{
|
{
|
||||||
switch(m_uPosition)
|
switch(m_uPosition)
|
||||||
{
|
{
|
||||||
case 1: _byte = m_uAD16Register.U8[0]; break;
|
case 1: _byte = m_uAD16Register.U8[0]; break;
|
||||||
case 2: _byte = m_uAD16Register.U8[1]; break;
|
case 2: _byte = m_uAD16Register.U8[1]; break;
|
||||||
case 3: _byte = m_uAD16Register.U8[2]; break;
|
case 3: _byte = m_uAD16Register.U8[2]; break;
|
||||||
case 4: _byte = m_uAD16Register.U8[3]; break;
|
case 4: _byte = m_uAD16Register.U8[3]; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_uPosition++;
|
m_uPosition++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,282 +1,282 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
|
|
||||||
#include "EXI_DeviceIPL.h"
|
#include "EXI_DeviceIPL.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
#include "MemoryUtil.h"
|
#include "MemoryUtil.h"
|
||||||
|
|
||||||
// english
|
// english
|
||||||
const unsigned char sram_dump[64] = {
|
const unsigned char sram_dump[64] = {
|
||||||
0x04, 0x6B, 0xFB, 0x91, 0x00, 0x00, 0x00, 0x00,
|
0x04, 0x6B, 0xFB, 0x91, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x40,
|
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x40,
|
||||||
0x05, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00,
|
0x05, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0xD2, 0x2B, 0x29, 0xD5, 0xC7, 0xAA, 0x12, 0xCB,
|
0xD2, 0x2B, 0x29, 0xD5, 0xC7, 0xAA, 0x12, 0xCB,
|
||||||
0x21, 0x27, 0xD1, 0x53, 0x00, 0x00, 0x00, 0x00,
|
0x21, 0x27, 0xD1, 0x53, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x86, 0x00, 0xFF, 0x4A, 0x00, 0x00, 0x00, 0x00
|
0x86, 0x00, 0xFF, 0x4A, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
// german
|
// german
|
||||||
const unsigned char sram_dump_german[64] ={
|
const unsigned char sram_dump_german[64] ={
|
||||||
0x1F, 0x66, 0xE0, 0x96, 0x00, 0x00, 0x00, 0x00,
|
0x1F, 0x66, 0xE0, 0x96, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x04, 0xEA, 0x19, 0x40,
|
0x00, 0x00, 0x00, 0x00, 0x04, 0xEA, 0x19, 0x40,
|
||||||
0x00, 0x00, 0x01, 0x3C, 0x12, 0xD5, 0xEA, 0xD3,
|
0x00, 0x00, 0x01, 0x3C, 0x12, 0xD5, 0xEA, 0xD3,
|
||||||
0x00, 0xFA, 0x2D, 0x33, 0x13, 0x41, 0x26, 0x03,
|
0x00, 0xFA, 0x2D, 0x33, 0x13, 0x41, 0x26, 0x03,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x84, 0xFF, 0x00, 0x00, 0x00, 0x00
|
0x00, 0x00, 0x84, 0xFF, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// We should provide an option to choose from the above, or figure out the checksum (the algo in yagcd seems wrong)
|
// We should provide an option to choose from the above, or figure out the checksum (the algo in yagcd seems wrong)
|
||||||
// so that people can change default language.
|
// so that people can change default language.
|
||||||
|
|
||||||
static const char iplver[0x100] = "(C) 1999-2001 Nintendo. All rights reserved."
|
static const char iplver[0x100] = "(C) 1999-2001 Nintendo. All rights reserved."
|
||||||
"(C) 1999 ArtX Inc. All rights reserved."
|
"(C) 1999 ArtX Inc. All rights reserved."
|
||||||
"PAL Revision 1.0 ";
|
"PAL Revision 1.0 ";
|
||||||
|
|
||||||
CEXIIPL::CEXIIPL() :
|
CEXIIPL::CEXIIPL() :
|
||||||
m_uPosition(0),
|
m_uPosition(0),
|
||||||
m_uAddress(0),
|
m_uAddress(0),
|
||||||
m_uRWOffset(0),
|
m_uRWOffset(0),
|
||||||
m_count(0)
|
m_count(0)
|
||||||
{
|
{
|
||||||
// Load the IPL
|
// Load the IPL
|
||||||
m_pIPL = (u8*)AllocateMemoryPages(ROM_SIZE);
|
m_pIPL = (u8*)AllocateMemoryPages(ROM_SIZE);
|
||||||
FILE* pStream = NULL;
|
FILE* pStream = NULL;
|
||||||
pStream = fopen(FONT_ANSI_FILE, "rb");
|
pStream = fopen(FONT_ANSI_FILE, "rb");
|
||||||
if (pStream != NULL)
|
if (pStream != NULL)
|
||||||
{
|
{
|
||||||
fseek(pStream, 0, SEEK_END);
|
fseek(pStream, 0, SEEK_END);
|
||||||
size_t filesize = (size_t)ftell(pStream);
|
size_t filesize = (size_t)ftell(pStream);
|
||||||
rewind(pStream);
|
rewind(pStream);
|
||||||
|
|
||||||
fread(m_pIPL + 0x001fcf00, 1, filesize, pStream);
|
fread(m_pIPL + 0x001fcf00, 1, filesize, pStream);
|
||||||
fclose(pStream);
|
fclose(pStream);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PanicAlert("Error: failed to load font_ansi.bin. Fonts may bug");
|
PanicAlert("Error: failed to load font_ansi.bin. Fonts may bug");
|
||||||
}
|
}
|
||||||
|
|
||||||
pStream = fopen(FONT_SJIS_FILE, "rb");
|
pStream = fopen(FONT_SJIS_FILE, "rb");
|
||||||
if (pStream != NULL)
|
if (pStream != NULL)
|
||||||
{
|
{
|
||||||
fseek(pStream, 0, SEEK_END);
|
fseek(pStream, 0, SEEK_END);
|
||||||
size_t filesize = (size_t)ftell(pStream);
|
size_t filesize = (size_t)ftell(pStream);
|
||||||
rewind(pStream);
|
rewind(pStream);
|
||||||
|
|
||||||
fread(m_pIPL + 0x001aff00, 1, filesize, pStream);
|
fread(m_pIPL + 0x001aff00, 1, filesize, pStream);
|
||||||
fclose(pStream);
|
fclose(pStream);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PanicAlert("Error: failed to load font_sjis.bin. Fonts may bug");
|
PanicAlert("Error: failed to load font_sjis.bin. Fonts may bug");
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(m_pIPL, iplver, sizeof(iplver));
|
memcpy(m_pIPL, iplver, sizeof(iplver));
|
||||||
|
|
||||||
// Clear RTC
|
// Clear RTC
|
||||||
memset(m_RTC, 0, sizeof(m_RTC));
|
memset(m_RTC, 0, sizeof(m_RTC));
|
||||||
|
|
||||||
// SRAM
|
// SRAM
|
||||||
pStream = fopen(Core::GetStartupParameter().m_strSRAM.c_str(), "rb");
|
pStream = fopen(Core::GetStartupParameter().m_strSRAM.c_str(), "rb");
|
||||||
if (pStream != NULL)
|
if (pStream != NULL)
|
||||||
{
|
{
|
||||||
fread(m_SRAM, 1, 64, pStream);
|
fread(m_SRAM, 1, 64, pStream);
|
||||||
fclose(pStream);
|
fclose(pStream);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(m_SRAM, sram_dump, sizeof(m_SRAM));
|
memcpy(m_SRAM, sram_dump, sizeof(m_SRAM));
|
||||||
}
|
}
|
||||||
// We Overwrite it here since it's possible on the GC to change the language as you please
|
// We Overwrite it here since it's possible on the GC to change the language as you please
|
||||||
m_SRAM[0x12] = Core::GetStartupParameter().SelectedLanguage;
|
m_SRAM[0x12] = Core::GetStartupParameter().SelectedLanguage;
|
||||||
|
|
||||||
WriteProtectMemory(m_pIPL, ROM_SIZE);
|
WriteProtectMemory(m_pIPL, ROM_SIZE);
|
||||||
m_uAddress = 0;
|
m_uAddress = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CEXIIPL::~CEXIIPL()
|
CEXIIPL::~CEXIIPL()
|
||||||
{
|
{
|
||||||
if (m_count > 0)
|
if (m_count > 0)
|
||||||
{
|
{
|
||||||
m_szBuffer[m_count] = 0x00;
|
m_szBuffer[m_count] = 0x00;
|
||||||
//MessageBox(NULL, m_szBuffer, "last message", MB_OK);
|
//MessageBox(NULL, m_szBuffer, "last message", MB_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_pIPL != NULL)
|
if (m_pIPL != NULL)
|
||||||
{
|
{
|
||||||
FreeMemoryPages(m_pIPL, ROM_SIZE);
|
FreeMemoryPages(m_pIPL, ROM_SIZE);
|
||||||
m_pIPL = NULL;
|
m_pIPL = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRAM
|
// SRAM
|
||||||
FILE* pStream = NULL;
|
FILE* pStream = NULL;
|
||||||
pStream = fopen(Core::GetStartupParameter().m_strSRAM.c_str(), "wb");
|
pStream = fopen(Core::GetStartupParameter().m_strSRAM.c_str(), "wb");
|
||||||
if (pStream != NULL)
|
if (pStream != NULL)
|
||||||
{
|
{
|
||||||
fwrite(m_SRAM, 1, 64, pStream);
|
fwrite(m_SRAM, 1, 64, pStream);
|
||||||
fclose(pStream);
|
fclose(pStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIIPL::SetCS(int _iCS)
|
void CEXIIPL::SetCS(int _iCS)
|
||||||
{
|
{
|
||||||
if (_iCS)
|
if (_iCS)
|
||||||
{ // cs transition to high
|
{ // cs transition to high
|
||||||
m_uPosition = 0;
|
m_uPosition = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CEXIIPL::IsPresent()
|
bool CEXIIPL::IsPresent()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIIPL::TransferByte(u8& _uByte)
|
void CEXIIPL::TransferByte(u8& _uByte)
|
||||||
{
|
{
|
||||||
// The first 4 bytes must be the address
|
// The first 4 bytes must be the address
|
||||||
// If we haven't read it, do it now
|
// If we haven't read it, do it now
|
||||||
if (m_uPosition < 4)
|
if (m_uPosition < 4)
|
||||||
{
|
{
|
||||||
m_uAddress <<= 8;
|
m_uAddress <<= 8;
|
||||||
m_uAddress |= _uByte;
|
m_uAddress |= _uByte;
|
||||||
m_uRWOffset = 0;
|
m_uRWOffset = 0;
|
||||||
_uByte = 0xFF;
|
_uByte = 0xFF;
|
||||||
|
|
||||||
// Check if the command is complete
|
// Check if the command is complete
|
||||||
if (m_uPosition == 3)
|
if (m_uPosition == 3)
|
||||||
{
|
{
|
||||||
// Get the time ...
|
// Get the time ...
|
||||||
u32 GCTime = CEXIIPL::GetGCTime();
|
u32 GCTime = CEXIIPL::GetGCTime();
|
||||||
u8* pGCTime = (u8*)&GCTime;
|
u8* pGCTime = (u8*)&GCTime;
|
||||||
for (int i=0; i<4; i++)
|
for (int i=0; i<4; i++)
|
||||||
{
|
{
|
||||||
m_RTC[i] = pGCTime[i^3];
|
m_RTC[i] = pGCTime[i^3];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
|
|
||||||
if ((m_uAddress & 0xF0000000) == 0xb0000000)
|
if ((m_uAddress & 0xF0000000) == 0xb0000000)
|
||||||
{
|
{
|
||||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something");
|
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something");
|
||||||
}
|
}
|
||||||
else if ((m_uAddress & 0xF0000000) == 0x30000000)
|
else if ((m_uAddress & 0xF0000000) == 0x30000000)
|
||||||
{
|
{
|
||||||
// wii stuff perhaps wii SRAM?
|
// wii stuff perhaps wii SRAM?
|
||||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something (perhaps SRAM?)");
|
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something (perhaps SRAM?)");
|
||||||
}
|
}
|
||||||
// debug only
|
// debug only
|
||||||
else if ((m_uAddress & 0x60000000) == 0)
|
else if ((m_uAddress & 0x60000000) == 0)
|
||||||
{
|
{
|
||||||
LOGV(EXPANSIONINTERFACE, 2, "EXI IPL-DEV: IPL access");
|
LOGV(EXPANSIONINTERFACE, 2, "EXI IPL-DEV: IPL access");
|
||||||
}
|
}
|
||||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20000000)
|
else if ((m_uAddress & 0x7FFFFF00) == 0x20000000)
|
||||||
{
|
{
|
||||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: RTC access");
|
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: RTC access");
|
||||||
}
|
}
|
||||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20000100)
|
else if ((m_uAddress & 0x7FFFFF00) == 0x20000100)
|
||||||
{
|
{
|
||||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: SRAM access");
|
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: SRAM access");
|
||||||
}
|
}
|
||||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20010000)
|
else if ((m_uAddress & 0x7FFFFF00) == 0x20010000)
|
||||||
{
|
{
|
||||||
LOGV(EXPANSIONINTERFACE, 3, "EXI IPL-DEV: UART");
|
LOGV(EXPANSIONINTERFACE, 3, "EXI IPL-DEV: UART");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_dbg_assert_(EXPANSIONINTERFACE, 0);
|
_dbg_assert_(EXPANSIONINTERFACE, 0);
|
||||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: illegal address %08x", m_uAddress);
|
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: illegal address %08x", m_uAddress);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// --- ROM ---
|
// --- ROM ---
|
||||||
//
|
//
|
||||||
if ((m_uAddress & 0x60000000) == 0)
|
if ((m_uAddress & 0x60000000) == 0)
|
||||||
{
|
{
|
||||||
if ((m_uAddress & 0x80000000) == 0)
|
if ((m_uAddress & 0x80000000) == 0)
|
||||||
_uByte = m_pIPL[((m_uAddress >> 6) & ROM_MASK) + m_uRWOffset];
|
_uByte = m_pIPL[((m_uAddress >> 6) & ROM_MASK) + m_uRWOffset];
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// --- Real Time Clock (RTC) ---
|
// --- Real Time Clock (RTC) ---
|
||||||
//
|
//
|
||||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20000000)
|
else if ((m_uAddress & 0x7FFFFF00) == 0x20000000)
|
||||||
{
|
{
|
||||||
if (m_uAddress & 0x80000000)
|
if (m_uAddress & 0x80000000)
|
||||||
m_RTC[(m_uAddress & 0x03) + m_uRWOffset] = _uByte;
|
m_RTC[(m_uAddress & 0x03) + m_uRWOffset] = _uByte;
|
||||||
else
|
else
|
||||||
_uByte = m_RTC[(m_uAddress & 0x03) + m_uRWOffset];
|
_uByte = m_RTC[(m_uAddress & 0x03) + m_uRWOffset];
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// --- SRAM ---
|
// --- SRAM ---
|
||||||
//
|
//
|
||||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20000100)
|
else if ((m_uAddress & 0x7FFFFF00) == 0x20000100)
|
||||||
{
|
{
|
||||||
if (m_uAddress & 0x80000000)
|
if (m_uAddress & 0x80000000)
|
||||||
m_SRAM[(m_uAddress & 0x3F) + m_uRWOffset] = _uByte;
|
m_SRAM[(m_uAddress & 0x3F) + m_uRWOffset] = _uByte;
|
||||||
else
|
else
|
||||||
_uByte = m_SRAM[(m_uAddress & 0x3F) + m_uRWOffset];
|
_uByte = m_SRAM[(m_uAddress & 0x3F) + m_uRWOffset];
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// --- UART ---
|
// --- UART ---
|
||||||
//
|
//
|
||||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20010000)
|
else if ((m_uAddress & 0x7FFFFF00) == 0x20010000)
|
||||||
{
|
{
|
||||||
if (m_uAddress & 0x80000000)
|
if (m_uAddress & 0x80000000)
|
||||||
{
|
{
|
||||||
m_szBuffer[m_count++] = _uByte;
|
m_szBuffer[m_count++] = _uByte;
|
||||||
if ((m_count >= 256) || (_uByte == 0xD))
|
if ((m_count >= 256) || (_uByte == 0xD))
|
||||||
{
|
{
|
||||||
m_szBuffer[m_count] = 0x00;
|
m_szBuffer[m_count] = 0x00;
|
||||||
LOG(OSREPORT, "%s", m_szBuffer);
|
LOG(OSREPORT, "%s", m_szBuffer);
|
||||||
memset(m_szBuffer, 0, sizeof(m_szBuffer));
|
memset(m_szBuffer, 0, sizeof(m_szBuffer));
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_uByte = 0x01; // dunno
|
_uByte = 0x01; // dunno
|
||||||
}
|
}
|
||||||
m_uRWOffset++;
|
m_uRWOffset++;
|
||||||
}
|
}
|
||||||
m_uPosition++;
|
m_uPosition++;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CEXIIPL::GetGCTime()
|
u32 CEXIIPL::GetGCTime()
|
||||||
{
|
{
|
||||||
// Get SRAM bias
|
// Get SRAM bias
|
||||||
u32 Bias;
|
u32 Bias;
|
||||||
|
|
||||||
for (int i=0; i<4; i++)
|
for (int i=0; i<4; i++)
|
||||||
{
|
{
|
||||||
((u8*)&Bias)[i] = sram_dump[0xc + (i^3)];
|
((u8*)&Bias)[i] = sram_dump[0xc + (i^3)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the time ...
|
// Get the time ...
|
||||||
const u32 cJanuary2000 = 0x386d35a1; // Seconds between 1.1.1970 and 1.1.2000
|
const u32 cJanuary2000 = 0x386d35a1; // Seconds between 1.1.1970 and 1.1.2000
|
||||||
u64 ltime = Common::Timer::GetTimeSinceJan1970();
|
u64 ltime = Common::Timer::GetTimeSinceJan1970();
|
||||||
return ((u32)ltime - cJanuary2000 - Bias);
|
return ((u32)ltime - cJanuary2000 - Bias);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,387 +1,387 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "FileUtil.h"
|
#include "FileUtil.h"
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
#include "../CoreTiming.h"
|
#include "../CoreTiming.h"
|
||||||
|
|
||||||
#include "EXI_Device.h"
|
#include "EXI_Device.h"
|
||||||
#include "EXI_DeviceMemoryCard.h"
|
#include "EXI_DeviceMemoryCard.h"
|
||||||
|
|
||||||
#define MC_STATUS_BUSY 0x80
|
#define MC_STATUS_BUSY 0x80
|
||||||
#define MC_STATUS_UNLOCKED 0x40
|
#define MC_STATUS_UNLOCKED 0x40
|
||||||
#define MC_STATUS_SLEEP 0x20
|
#define MC_STATUS_SLEEP 0x20
|
||||||
#define MC_STATUS_ERASEERROR 0x10
|
#define MC_STATUS_ERASEERROR 0x10
|
||||||
#define MC_STATUS_PROGRAMEERROR 0x08
|
#define MC_STATUS_PROGRAMEERROR 0x08
|
||||||
#define MC_STATUS_READY 0x01
|
#define MC_STATUS_READY 0x01
|
||||||
|
|
||||||
static CEXIMemoryCard *cards[2];
|
static CEXIMemoryCard *cards[2];
|
||||||
|
|
||||||
void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate)
|
void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
CEXIMemoryCard *ptr = cards[userdata];
|
CEXIMemoryCard *ptr = cards[userdata];
|
||||||
ptr->Flush();
|
ptr->Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
CEXIMemoryCard::CEXIMemoryCard(const std::string& _rName, const std::string& _rFilename, int _card_index) :
|
CEXIMemoryCard::CEXIMemoryCard(const std::string& _rName, const std::string& _rFilename, int _card_index) :
|
||||||
m_strFilename(_rFilename)
|
m_strFilename(_rFilename)
|
||||||
{
|
{
|
||||||
this->card_index = _card_index;
|
this->card_index = _card_index;
|
||||||
cards[_card_index] = this;
|
cards[_card_index] = this;
|
||||||
et_this_card = CoreTiming::RegisterEvent(_rName.c_str(), FlushCallback);
|
et_this_card = CoreTiming::RegisterEvent(_rName.c_str(), FlushCallback);
|
||||||
|
|
||||||
interruptSwitch = 0;
|
interruptSwitch = 0;
|
||||||
m_bInterruptSet = 0;
|
m_bInterruptSet = 0;
|
||||||
command = 0;
|
command = 0;
|
||||||
status = MC_STATUS_BUSY | MC_STATUS_UNLOCKED | MC_STATUS_READY;
|
status = MC_STATUS_BUSY | MC_STATUS_UNLOCKED | MC_STATUS_READY;
|
||||||
m_uPosition = 0;
|
m_uPosition = 0;
|
||||||
memset(programming_buffer, 0, sizeof(programming_buffer));
|
memset(programming_buffer, 0, sizeof(programming_buffer));
|
||||||
formatDelay = 0;
|
formatDelay = 0;
|
||||||
|
|
||||||
//Nintendo Memory Card EXI IDs
|
//Nintendo Memory Card EXI IDs
|
||||||
//0x00000004 Memory Card 59 4Mbit
|
//0x00000004 Memory Card 59 4Mbit
|
||||||
//0x00000008 Memory Card 123 8Mb
|
//0x00000008 Memory Card 123 8Mb
|
||||||
//0x00000010 Memory Card 251 16Mb
|
//0x00000010 Memory Card 251 16Mb
|
||||||
//0x00000020 Memory Card 507 32Mb
|
//0x00000020 Memory Card 507 32Mb
|
||||||
//0x00000040 Memory Card 1019 64Mb
|
//0x00000040 Memory Card 1019 64Mb
|
||||||
//0x00000080 Memory Card 2043 128Mb
|
//0x00000080 Memory Card 2043 128Mb
|
||||||
|
|
||||||
//0x00000510 16Mb "bigben" card
|
//0x00000510 16Mb "bigben" card
|
||||||
//card_id = 0xc243;
|
//card_id = 0xc243;
|
||||||
|
|
||||||
card_id = 0xc221; // It's a nintendo brand memcard
|
card_id = 0xc221; // It's a nintendo brand memcard
|
||||||
|
|
||||||
FILE* pFile = NULL;
|
FILE* pFile = NULL;
|
||||||
pFile = fopen(m_strFilename.c_str(), "rb");
|
pFile = fopen(m_strFilename.c_str(), "rb");
|
||||||
if (pFile)
|
if (pFile)
|
||||||
{
|
{
|
||||||
fseek( pFile, 0L, SEEK_END );
|
fseek( pFile, 0L, SEEK_END );
|
||||||
u64 MemFileSize = ftell( pFile );
|
u64 MemFileSize = ftell( pFile );
|
||||||
|
|
||||||
switch ((MemFileSize / (8 * 1024))-5) // Convert the filesize in bytes to the "nintendo-size"
|
switch ((MemFileSize / (8 * 1024))-5) // Convert the filesize in bytes to the "nintendo-size"
|
||||||
{
|
{
|
||||||
case 59:
|
case 59:
|
||||||
nintendo_card_id = 0x00000004;
|
nintendo_card_id = 0x00000004;
|
||||||
memory_card_size = 512 * 1024;
|
memory_card_size = 512 * 1024;
|
||||||
break;
|
break;
|
||||||
case 123:
|
case 123:
|
||||||
nintendo_card_id = 0x00000008;
|
nintendo_card_id = 0x00000008;
|
||||||
memory_card_size = 1024 * 1024;
|
memory_card_size = 1024 * 1024;
|
||||||
break;
|
break;
|
||||||
case 251:
|
case 251:
|
||||||
nintendo_card_id = 0x00000010;
|
nintendo_card_id = 0x00000010;
|
||||||
memory_card_size = 2 * 1024 * 1024;
|
memory_card_size = 2 * 1024 * 1024;
|
||||||
break;
|
break;
|
||||||
case 507:
|
case 507:
|
||||||
nintendo_card_id = 0x00000020;
|
nintendo_card_id = 0x00000020;
|
||||||
memory_card_size = 4 * 1024 * 1024;
|
memory_card_size = 4 * 1024 * 1024;
|
||||||
break;
|
break;
|
||||||
case 1019:
|
case 1019:
|
||||||
nintendo_card_id = 0x00000040;
|
nintendo_card_id = 0x00000040;
|
||||||
memory_card_size = 8 * 1024 * 1024;
|
memory_card_size = 8 * 1024 * 1024;
|
||||||
break;
|
break;
|
||||||
case 2043:
|
case 2043:
|
||||||
default:
|
default:
|
||||||
nintendo_card_id = 0x00000080;
|
nintendo_card_id = 0x00000080;
|
||||||
memory_card_size = 16 * 1024 * 1024;
|
memory_card_size = 16 * 1024 * 1024;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return to start otherwise the mem card is "corrupt"
|
// Return to start otherwise the mem card is "corrupt"
|
||||||
fseek( pFile,0L,SEEK_SET);
|
fseek( pFile,0L,SEEK_SET);
|
||||||
|
|
||||||
memory_card_content = new u8[memory_card_size];
|
memory_card_content = new u8[memory_card_size];
|
||||||
memset(memory_card_content, 0xFF, memory_card_size);
|
memset(memory_card_content, 0xFF, memory_card_size);
|
||||||
|
|
||||||
LOG(EXPANSIONINTERFACE, "Reading memory card %s", m_strFilename.c_str());
|
LOG(EXPANSIONINTERFACE, "Reading memory card %s", m_strFilename.c_str());
|
||||||
fread(memory_card_content, 1, memory_card_size, pFile);
|
fread(memory_card_content, 1, memory_card_size, pFile);
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Create a new 128Mb memcard
|
// Create a new 128Mb memcard
|
||||||
nintendo_card_id = 0x00000080;
|
nintendo_card_id = 0x00000080;
|
||||||
memory_card_size = 16 * 1024 * 1024;
|
memory_card_size = 16 * 1024 * 1024;
|
||||||
|
|
||||||
memory_card_content = new u8[memory_card_size];
|
memory_card_content = new u8[memory_card_size];
|
||||||
memset(memory_card_content, 0xFF, memory_card_size);
|
memset(memory_card_content, 0xFF, memory_card_size);
|
||||||
|
|
||||||
LOG(EXPANSIONINTERFACE, "No memory card found. Will create new.");
|
LOG(EXPANSIONINTERFACE, "No memory card found. Will create new.");
|
||||||
Flush();
|
Flush();
|
||||||
Core::DisplayMessage(StringFromFormat("Wrote memory card contents to %s", m_strFilename.c_str()), 4000);
|
Core::DisplayMessage(StringFromFormat("Wrote memory card contents to %s", m_strFilename.c_str()), 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIMemoryCard::Flush(bool exiting)
|
void CEXIMemoryCard::Flush(bool exiting)
|
||||||
{
|
{
|
||||||
FILE* pFile = NULL;
|
FILE* pFile = NULL;
|
||||||
pFile = fopen(m_strFilename.c_str(), "wb");
|
pFile = fopen(m_strFilename.c_str(), "wb");
|
||||||
if (!pFile)
|
if (!pFile)
|
||||||
{
|
{
|
||||||
std::string dir;
|
std::string dir;
|
||||||
SplitPath(m_strFilename, &dir, 0, 0);
|
SplitPath(m_strFilename, &dir, 0, 0);
|
||||||
if(!File::IsDirectory(dir.c_str()))
|
if(!File::IsDirectory(dir.c_str()))
|
||||||
File::CreateDir(dir.c_str());
|
File::CreateDir(dir.c_str());
|
||||||
pFile = fopen(m_strFilename.c_str(), "wb");
|
pFile = fopen(m_strFilename.c_str(), "wb");
|
||||||
}
|
}
|
||||||
if (!pFile) //Note - pFile changed inside above if
|
if (!pFile) //Note - pFile changed inside above if
|
||||||
{
|
{
|
||||||
PanicAlert("Could not write memory card file %s.\n\n"
|
PanicAlert("Could not write memory card file %s.\n\n"
|
||||||
"Are you running Dolphin from a CD/DVD, or is the save file maybe write protected?", m_strFilename.c_str());
|
"Are you running Dolphin from a CD/DVD, or is the save file maybe write protected?", m_strFilename.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fwrite(memory_card_content, memory_card_size, 1, pFile);
|
fwrite(memory_card_content, memory_card_size, 1, pFile);
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
if (!exiting)
|
if (!exiting)
|
||||||
Core::DisplayMessage(StringFromFormat("Wrote memory card contents to %s", GetFileName().c_str()), 4000);
|
Core::DisplayMessage(StringFromFormat("Wrote memory card contents to %s", GetFileName().c_str()), 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CEXIMemoryCard::~CEXIMemoryCard()
|
CEXIMemoryCard::~CEXIMemoryCard()
|
||||||
{
|
{
|
||||||
Flush(true);
|
Flush(true);
|
||||||
delete [] memory_card_content;
|
delete [] memory_card_content;
|
||||||
memory_card_content = NULL;
|
memory_card_content = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CEXIMemoryCard::IsPresent()
|
bool CEXIMemoryCard::IsPresent()
|
||||||
{
|
{
|
||||||
//return false;
|
//return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIMemoryCard::SetCS(int cs)
|
void CEXIMemoryCard::SetCS(int cs)
|
||||||
{
|
{
|
||||||
if (cs) // not-selected to selected
|
if (cs) // not-selected to selected
|
||||||
m_uPosition = 0;
|
m_uPosition = 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (command)
|
switch (command)
|
||||||
{
|
{
|
||||||
case cmdSectorErase:
|
case cmdSectorErase:
|
||||||
if (m_uPosition > 2)
|
if (m_uPosition > 2)
|
||||||
{
|
{
|
||||||
memset(memory_card_content + (address & (memory_card_size-1)), 0xFF, 0x2000);
|
memset(memory_card_content + (address & (memory_card_size-1)), 0xFF, 0x2000);
|
||||||
status |= MC_STATUS_BUSY;
|
status |= MC_STATUS_BUSY;
|
||||||
status &= ~MC_STATUS_READY;
|
status &= ~MC_STATUS_READY;
|
||||||
|
|
||||||
//???
|
//???
|
||||||
|
|
||||||
status |= MC_STATUS_READY;
|
status |= MC_STATUS_READY;
|
||||||
status &= ~MC_STATUS_BUSY;
|
status &= ~MC_STATUS_BUSY;
|
||||||
|
|
||||||
m_bInterruptSet = 1;
|
m_bInterruptSet = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cmdChipErase:
|
case cmdChipErase:
|
||||||
if (m_uPosition > 2)
|
if (m_uPosition > 2)
|
||||||
{
|
{
|
||||||
memset(memory_card_content, 0xFF, memory_card_size);
|
memset(memory_card_content, 0xFF, memory_card_size);
|
||||||
status &= ~MC_STATUS_BUSY;
|
status &= ~MC_STATUS_BUSY;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cmdPageProgram:
|
case cmdPageProgram:
|
||||||
if (m_uPosition >= 5)
|
if (m_uPosition >= 5)
|
||||||
{
|
{
|
||||||
int count = m_uPosition - 5;
|
int count = m_uPosition - 5;
|
||||||
int i=0;
|
int i=0;
|
||||||
status &= ~0x80;
|
status &= ~0x80;
|
||||||
|
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
memory_card_content[address] = programming_buffer[i++];
|
memory_card_content[address] = programming_buffer[i++];
|
||||||
i &= 127;
|
i &= 127;
|
||||||
address = (address & ~0x1FF) | ((address+1) & 0x1FF);
|
address = (address & ~0x1FF) | ((address+1) & 0x1FF);
|
||||||
}
|
}
|
||||||
|
|
||||||
status |= MC_STATUS_READY;
|
status |= MC_STATUS_READY;
|
||||||
status &= ~MC_STATUS_BUSY;
|
status &= ~MC_STATUS_BUSY;
|
||||||
|
|
||||||
m_bInterruptSet = 1;
|
m_bInterruptSet = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Page written to memory card, not just to buffer - let's schedule a flush 0.5b cycles into the future (1 sec)
|
// Page written to memory card, not just to buffer - let's schedule a flush 0.5b cycles into the future (1 sec)
|
||||||
// But first we unschedule already scheduled flushes - no point in flushing once per page for a large write.
|
// But first we unschedule already scheduled flushes - no point in flushing once per page for a large write.
|
||||||
CoreTiming::RemoveEvent(et_this_card);
|
CoreTiming::RemoveEvent(et_this_card);
|
||||||
CoreTiming::ScheduleEvent(500000000, et_this_card, card_index);
|
CoreTiming::ScheduleEvent(500000000, et_this_card, card_index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIMemoryCard::Update()
|
void CEXIMemoryCard::Update()
|
||||||
{
|
{
|
||||||
if (formatDelay)
|
if (formatDelay)
|
||||||
{
|
{
|
||||||
formatDelay--;
|
formatDelay--;
|
||||||
|
|
||||||
if (!formatDelay)
|
if (!formatDelay)
|
||||||
{
|
{
|
||||||
status |= MC_STATUS_READY;
|
status |= MC_STATUS_READY;
|
||||||
status &= ~MC_STATUS_BUSY;
|
status &= ~MC_STATUS_BUSY;
|
||||||
|
|
||||||
m_bInterruptSet = 1;
|
m_bInterruptSet = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CEXIMemoryCard::IsInterruptSet()
|
bool CEXIMemoryCard::IsInterruptSet()
|
||||||
{
|
{
|
||||||
if (interruptSwitch)
|
if (interruptSwitch)
|
||||||
return m_bInterruptSet;
|
return m_bInterruptSet;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIMemoryCard::TransferByte(u8 &byte)
|
void CEXIMemoryCard::TransferByte(u8 &byte)
|
||||||
{
|
{
|
||||||
LOGV(EXPANSIONINTERFACE, 3, "EXI MEMCARD: > %02x", byte);
|
LOGV(EXPANSIONINTERFACE, 3, "EXI MEMCARD: > %02x", byte);
|
||||||
if (m_uPosition == 0)
|
if (m_uPosition == 0)
|
||||||
{
|
{
|
||||||
command = byte; // first byte is command
|
command = byte; // first byte is command
|
||||||
byte = 0xFF; // would be tristate, but we don't care.
|
byte = 0xFF; // would be tristate, but we don't care.
|
||||||
LOGV(EXPANSIONINTERFACE, 1, "EXI MEMCARD: command %02x", byte)
|
LOGV(EXPANSIONINTERFACE, 1, "EXI MEMCARD: command %02x", byte)
|
||||||
|
|
||||||
if(command == cmdClearStatus)
|
if(command == cmdClearStatus)
|
||||||
{
|
{
|
||||||
status &= ~MC_STATUS_PROGRAMEERROR;
|
status &= ~MC_STATUS_PROGRAMEERROR;
|
||||||
status &= ~MC_STATUS_ERASEERROR;
|
status &= ~MC_STATUS_ERASEERROR;
|
||||||
|
|
||||||
status |= MC_STATUS_READY;
|
status |= MC_STATUS_READY;
|
||||||
|
|
||||||
m_bInterruptSet = 0;
|
m_bInterruptSet = 0;
|
||||||
|
|
||||||
byte = 0xFF;
|
byte = 0xFF;
|
||||||
m_uPosition = 0;
|
m_uPosition = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (command)
|
switch (command)
|
||||||
{
|
{
|
||||||
case cmdNintendoID:
|
case cmdNintendoID:
|
||||||
//
|
//
|
||||||
// nintendo card:
|
// nintendo card:
|
||||||
// 00 | 80 00 00 00 10 00 00 00
|
// 00 | 80 00 00 00 10 00 00 00
|
||||||
// "bigben" card:
|
// "bigben" card:
|
||||||
// 00 | ff 00 00 05 10 00 00 00 00 00 00 00 00 00 00
|
// 00 | ff 00 00 05 10 00 00 00 00 00 00 00 00 00 00
|
||||||
// we do it the nintendo way.
|
// we do it the nintendo way.
|
||||||
if (m_uPosition == 1)
|
if (m_uPosition == 1)
|
||||||
byte = 0x80; // dummy cycle
|
byte = 0x80; // dummy cycle
|
||||||
else
|
else
|
||||||
byte = (u8)(nintendo_card_id >> (24-(((m_uPosition-2) & 3) * 8)));
|
byte = (u8)(nintendo_card_id >> (24-(((m_uPosition-2) & 3) * 8)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cmdReadArray:
|
case cmdReadArray:
|
||||||
switch (m_uPosition)
|
switch (m_uPosition)
|
||||||
{
|
{
|
||||||
case 1: // AD1
|
case 1: // AD1
|
||||||
address = byte << 17;
|
address = byte << 17;
|
||||||
byte = 0xFF;
|
byte = 0xFF;
|
||||||
break;
|
break;
|
||||||
case 2: // AD2
|
case 2: // AD2
|
||||||
address |= byte << 9;
|
address |= byte << 9;
|
||||||
break;
|
break;
|
||||||
case 3: // AD3
|
case 3: // AD3
|
||||||
address |= (byte & 3) << 7;
|
address |= (byte & 3) << 7;
|
||||||
break;
|
break;
|
||||||
case 4: // BA
|
case 4: // BA
|
||||||
address |= (byte & 0x7F);
|
address |= (byte & 0x7F);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (m_uPosition > 1) // not specified for 1..8, anyway
|
if (m_uPosition > 1) // not specified for 1..8, anyway
|
||||||
{
|
{
|
||||||
byte = memory_card_content[address & (memory_card_size-1)];
|
byte = memory_card_content[address & (memory_card_size-1)];
|
||||||
// after 9 bytes, we start incrementing the address,
|
// after 9 bytes, we start incrementing the address,
|
||||||
// but only the sector offset - the pointer wraps around
|
// but only the sector offset - the pointer wraps around
|
||||||
if (m_uPosition >= 9)
|
if (m_uPosition >= 9)
|
||||||
address = (address & ~0x1FF) | ((address+1) & 0x1FF);
|
address = (address & ~0x1FF) | ((address+1) & 0x1FF);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cmdReadStatus:
|
case cmdReadStatus:
|
||||||
// (unspecified for byte 1)
|
// (unspecified for byte 1)
|
||||||
byte = status;
|
byte = status;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cmdReadID:
|
case cmdReadID:
|
||||||
if (m_uPosition == 1) // (unspecified)
|
if (m_uPosition == 1) // (unspecified)
|
||||||
byte = (u8)(card_id >> 8);
|
byte = (u8)(card_id >> 8);
|
||||||
else
|
else
|
||||||
byte = (u8)((m_uPosition & 1) ? (card_id) : (card_id >> 8));
|
byte = (u8)((m_uPosition & 1) ? (card_id) : (card_id >> 8));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cmdSectorErase:
|
case cmdSectorErase:
|
||||||
switch (m_uPosition)
|
switch (m_uPosition)
|
||||||
{
|
{
|
||||||
case 1: // AD1
|
case 1: // AD1
|
||||||
address = byte << 17;
|
address = byte << 17;
|
||||||
break;
|
break;
|
||||||
case 2: // AD2
|
case 2: // AD2
|
||||||
address |= byte << 9;
|
address |= byte << 9;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
byte = 0xFF;
|
byte = 0xFF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cmdSetInterrupt:
|
case cmdSetInterrupt:
|
||||||
if (m_uPosition == 1)
|
if (m_uPosition == 1)
|
||||||
{
|
{
|
||||||
interruptSwitch = byte;
|
interruptSwitch = byte;
|
||||||
}
|
}
|
||||||
byte = 0xFF;
|
byte = 0xFF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cmdChipErase:
|
case cmdChipErase:
|
||||||
byte = 0xFF;
|
byte = 0xFF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cmdPageProgram:
|
case cmdPageProgram:
|
||||||
switch (m_uPosition)
|
switch (m_uPosition)
|
||||||
{
|
{
|
||||||
case 1: // AD1
|
case 1: // AD1
|
||||||
address = byte << 17;
|
address = byte << 17;
|
||||||
break;
|
break;
|
||||||
case 2: // AD2
|
case 2: // AD2
|
||||||
address |= byte << 9;
|
address |= byte << 9;
|
||||||
break;
|
break;
|
||||||
case 3: // AD3
|
case 3: // AD3
|
||||||
address |= (byte & 3) << 7;
|
address |= (byte & 3) << 7;
|
||||||
break;
|
break;
|
||||||
case 4: // BA
|
case 4: // BA
|
||||||
address |= (byte & 0x7F);
|
address |= (byte & 0x7F);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_uPosition >= 5)
|
if(m_uPosition >= 5)
|
||||||
programming_buffer[((m_uPosition - 5) & 0x7F)] = byte; // wrap around after 128 bytes
|
programming_buffer[((m_uPosition - 5) & 0x7F)] = byte; // wrap around after 128 bytes
|
||||||
|
|
||||||
byte = 0xFF;
|
byte = 0xFF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG(EXPANSIONINTERFACE, "EXI MEMCARD: unknown command byte %02x\n", byte);
|
LOG(EXPANSIONINTERFACE, "EXI MEMCARD: unknown command byte %02x\n", byte);
|
||||||
byte = 0xFF;
|
byte = 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_uPosition++;
|
m_uPosition++;
|
||||||
LOGV(EXPANSIONINTERFACE, 3, "EXI MEMCARD: < %02x", byte);
|
LOGV(EXPANSIONINTERFACE, 3, "EXI MEMCARD: < %02x", byte);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,147 +1,147 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
#include "PeripheralInterface.h"
|
#include "PeripheralInterface.h"
|
||||||
#include "CommandProcessor.h"
|
#include "CommandProcessor.h"
|
||||||
#include "Memmap.h"
|
#include "Memmap.h"
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
|
|
||||||
#include "GPFifo.h"
|
#include "GPFifo.h"
|
||||||
|
|
||||||
namespace GPFifo
|
namespace GPFifo
|
||||||
{
|
{
|
||||||
|
|
||||||
// 32 Byte gather pipe with extra space
|
// 32 Byte gather pipe with extra space
|
||||||
// Overfilling is no problem (up to the real limit), CheckGatherPipe will blast the
|
// Overfilling is no problem (up to the real limit), CheckGatherPipe will blast the
|
||||||
// contents in nicely sized chunks
|
// contents in nicely sized chunks
|
||||||
|
|
||||||
// Other optimizations to think about:
|
// Other optimizations to think about:
|
||||||
|
|
||||||
// If the gp is NOT linked to the fifo, just blast to memory byte by word
|
// If the gp is NOT linked to the fifo, just blast to memory byte by word
|
||||||
// If the gp IS linked to the fifo, use a fast wrapping buffer and skip writing to memory
|
// If the gp IS linked to the fifo, use a fast wrapping buffer and skip writing to memory
|
||||||
|
|
||||||
// Both of these should actually work! Only problem is that we have to decide at run time,
|
// Both of these should actually work! Only problem is that we have to decide at run time,
|
||||||
// the same function could use both methods. Compile 2 different versions of each such block?
|
// the same function could use both methods. Compile 2 different versions of each such block?
|
||||||
|
|
||||||
u8 GC_ALIGNED32(m_gatherPipe[GATHER_PIPE_SIZE*16]); //more room, for the fastmodes
|
u8 GC_ALIGNED32(m_gatherPipe[GATHER_PIPE_SIZE*16]); //more room, for the fastmodes
|
||||||
|
|
||||||
// pipe counter
|
// pipe counter
|
||||||
u32 m_gatherPipeCount = 0;
|
u32 m_gatherPipeCount = 0;
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
p.Do(m_gatherPipe);
|
p.Do(m_gatherPipe);
|
||||||
p.Do(m_gatherPipeCount);
|
p.Do(m_gatherPipeCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
ResetGatherPipe();
|
ResetGatherPipe();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsEmpty() {
|
bool IsEmpty() {
|
||||||
return m_gatherPipeCount == 0;
|
return m_gatherPipeCount == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetGatherPipe()
|
void ResetGatherPipe()
|
||||||
{
|
{
|
||||||
m_gatherPipeCount = 0;
|
m_gatherPipeCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckGatherPipe()
|
void CheckGatherPipe()
|
||||||
{
|
{
|
||||||
while (m_gatherPipeCount >= GATHER_PIPE_SIZE)
|
while (m_gatherPipeCount >= GATHER_PIPE_SIZE)
|
||||||
{
|
{
|
||||||
// copy the GatherPipe
|
// copy the GatherPipe
|
||||||
memcpy(Memory::GetPointer(CPeripheralInterface::Fifo_CPUWritePointer), m_gatherPipe, GATHER_PIPE_SIZE);
|
memcpy(Memory::GetPointer(CPeripheralInterface::Fifo_CPUWritePointer), m_gatherPipe, GATHER_PIPE_SIZE);
|
||||||
|
|
||||||
// [F|RES]: i thought GP is forced to mem1 ... strange
|
// [F|RES]: i thought GP is forced to mem1 ... strange
|
||||||
// memcpy(&Memory::GetMainRAMPtr()[CPeripheralInterface::Fifo_CPUWritePointer], m_gatherPipe, GATHER_PIPE_SIZE);
|
// memcpy(&Memory::GetMainRAMPtr()[CPeripheralInterface::Fifo_CPUWritePointer], m_gatherPipe, GATHER_PIPE_SIZE);
|
||||||
|
|
||||||
// move back the spill bytes
|
// move back the spill bytes
|
||||||
m_gatherPipeCount -= GATHER_PIPE_SIZE;
|
m_gatherPipeCount -= GATHER_PIPE_SIZE;
|
||||||
// This could be dangerous, memmove or ?
|
// This could be dangerous, memmove or ?
|
||||||
// Assuming that memcpy does its thing in the ordinary direction, there should be no problem.
|
// Assuming that memcpy does its thing in the ordinary direction, there should be no problem.
|
||||||
// Actually, this shouldn't ever be necessary. If we're above 2 "blocks" of data,
|
// Actually, this shouldn't ever be necessary. If we're above 2 "blocks" of data,
|
||||||
// the above memcpy could take care of that easily. TODO
|
// the above memcpy could take care of that easily. TODO
|
||||||
memmove(m_gatherPipe, m_gatherPipe + GATHER_PIPE_SIZE, m_gatherPipeCount);
|
memmove(m_gatherPipe, m_gatherPipe + GATHER_PIPE_SIZE, m_gatherPipeCount);
|
||||||
|
|
||||||
// increase the CPUWritePointer
|
// increase the CPUWritePointer
|
||||||
CPeripheralInterface::Fifo_CPUWritePointer += GATHER_PIPE_SIZE;
|
CPeripheralInterface::Fifo_CPUWritePointer += GATHER_PIPE_SIZE;
|
||||||
if (CPeripheralInterface::Fifo_CPUWritePointer > CPeripheralInterface::Fifo_CPUEnd)
|
if (CPeripheralInterface::Fifo_CPUWritePointer > CPeripheralInterface::Fifo_CPUEnd)
|
||||||
_assert_msg_(DYNA_REC, 0, "Fifo_CPUWritePointer out of bounds");
|
_assert_msg_(DYNA_REC, 0, "Fifo_CPUWritePointer out of bounds");
|
||||||
|
|
||||||
if (CPeripheralInterface::Fifo_CPUWritePointer >= CPeripheralInterface::Fifo_CPUEnd)
|
if (CPeripheralInterface::Fifo_CPUWritePointer >= CPeripheralInterface::Fifo_CPUEnd)
|
||||||
CPeripheralInterface::Fifo_CPUWritePointer = CPeripheralInterface::Fifo_CPUBase;
|
CPeripheralInterface::Fifo_CPUWritePointer = CPeripheralInterface::Fifo_CPUBase;
|
||||||
|
|
||||||
CommandProcessor::GatherPipeBursted();
|
CommandProcessor::GatherPipeBursted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write8(const u8 _iValue, const u32 _iAddress)
|
void Write8(const u8 _iValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
// LOG(GPFIFO, "GPFIFO #%x: 0x%02x",CPeripheralInterface::Fifo_CPUWritePointer+m_gatherPipeCount, _iValue);
|
// LOG(GPFIFO, "GPFIFO #%x: 0x%02x",CPeripheralInterface::Fifo_CPUWritePointer+m_gatherPipeCount, _iValue);
|
||||||
m_gatherPipe[m_gatherPipeCount] = _iValue;
|
m_gatherPipe[m_gatherPipeCount] = _iValue;
|
||||||
m_gatherPipeCount++;
|
m_gatherPipeCount++;
|
||||||
CheckGatherPipe();
|
CheckGatherPipe();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write16(const u16 _iValue, const u32 _iAddress)
|
void Write16(const u16 _iValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
// LOG(GPFIFO, "GPFIFO #%x: 0x%04x",CPeripheralInterface::Fifo_CPUWritePointer+m_gatherPipeCount, _iValue);
|
// LOG(GPFIFO, "GPFIFO #%x: 0x%04x",CPeripheralInterface::Fifo_CPUWritePointer+m_gatherPipeCount, _iValue);
|
||||||
*(u16*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap16(_iValue);
|
*(u16*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap16(_iValue);
|
||||||
m_gatherPipeCount += 2;
|
m_gatherPipeCount += 2;
|
||||||
CheckGatherPipe();
|
CheckGatherPipe();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write32(const u32 _iValue, const u32 _iAddress)
|
void Write32(const u32 _iValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
float floatvalue = *(float*)&_iValue;
|
float floatvalue = *(float*)&_iValue;
|
||||||
// LOG(GPFIFO, "GPFIFO #%x: 0x%08x / %f",CPeripheralInterface::Fifo_CPUWritePointer+m_gatherPipeCount, _iValue, floatvalue);
|
// LOG(GPFIFO, "GPFIFO #%x: 0x%08x / %f",CPeripheralInterface::Fifo_CPUWritePointer+m_gatherPipeCount, _iValue, floatvalue);
|
||||||
#endif
|
#endif
|
||||||
*(u32*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap32(_iValue);
|
*(u32*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap32(_iValue);
|
||||||
m_gatherPipeCount += 4;
|
m_gatherPipeCount += 4;
|
||||||
CheckGatherPipe();
|
CheckGatherPipe();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastWrite8(const u8 _iValue)
|
void FastWrite8(const u8 _iValue)
|
||||||
{
|
{
|
||||||
m_gatherPipe[m_gatherPipeCount] = _iValue;
|
m_gatherPipe[m_gatherPipeCount] = _iValue;
|
||||||
m_gatherPipeCount++;
|
m_gatherPipeCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastWrite16(const u16 _iValue)
|
void FastWrite16(const u16 _iValue)
|
||||||
{
|
{
|
||||||
*(u16*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap16(_iValue);
|
*(u16*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap16(_iValue);
|
||||||
m_gatherPipeCount += 2;
|
m_gatherPipeCount += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastWrite32(const u32 _iValue)
|
void FastWrite32(const u32 _iValue)
|
||||||
{
|
{
|
||||||
*(u32*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap32(_iValue);
|
*(u32*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap32(_iValue);
|
||||||
m_gatherPipeCount += 4;
|
m_gatherPipeCount += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastWriteEnd()
|
void FastWriteEnd()
|
||||||
{
|
{
|
||||||
CheckGatherPipe();
|
CheckGatherPipe();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace GPFifo
|
} // end of namespace GPFifo
|
||||||
|
|
|
@ -1,107 +1,107 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Thunk.h"
|
#include "Thunk.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
#include "HW.h"
|
#include "HW.h"
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "CPU.h"
|
#include "CPU.h"
|
||||||
#include "CommandProcessor.h"
|
#include "CommandProcessor.h"
|
||||||
#include "DSP.h"
|
#include "DSP.h"
|
||||||
#include "DVDInterface.h"
|
#include "DVDInterface.h"
|
||||||
#include "EXI.h"
|
#include "EXI.h"
|
||||||
#include "GPFifo.h"
|
#include "GPFifo.h"
|
||||||
#include "Memmap.h"
|
#include "Memmap.h"
|
||||||
#include "PeripheralInterface.h"
|
#include "PeripheralInterface.h"
|
||||||
#include "PixelEngine.h"
|
#include "PixelEngine.h"
|
||||||
#include "SerialInterface.h"
|
#include "SerialInterface.h"
|
||||||
#include "AudioInterface.h"
|
#include "AudioInterface.h"
|
||||||
#include "VideoInterface.h"
|
#include "VideoInterface.h"
|
||||||
#include "WII_IPC.h"
|
#include "WII_IPC.h"
|
||||||
#include "../Plugins/Plugin_Video.h"
|
#include "../Plugins/Plugin_Video.h"
|
||||||
#include "../CoreTiming.h"
|
#include "../CoreTiming.h"
|
||||||
#include "SystemTimers.h"
|
#include "SystemTimers.h"
|
||||||
#include "../IPC_HLE/WII_IPC_HLE.h"
|
#include "../IPC_HLE/WII_IPC_HLE.h"
|
||||||
#include "../State.h"
|
#include "../State.h"
|
||||||
#include "../PowerPC/PPCAnalyst.h"
|
#include "../PowerPC/PPCAnalyst.h"
|
||||||
|
|
||||||
namespace HW
|
namespace HW
|
||||||
{
|
{
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
CoreTiming::Init();
|
CoreTiming::Init();
|
||||||
PPCAnalyst::Init();
|
PPCAnalyst::Init();
|
||||||
|
|
||||||
Thunk_Init(); // not really hw, but this way we know it's inited early :P
|
Thunk_Init(); // not really hw, but this way we know it's inited early :P
|
||||||
State_Init();
|
State_Init();
|
||||||
|
|
||||||
// Init the whole Hardware
|
// Init the whole Hardware
|
||||||
AudioInterface::Init();
|
AudioInterface::Init();
|
||||||
PixelEngine::Init();
|
PixelEngine::Init();
|
||||||
CommandProcessor::Init();
|
CommandProcessor::Init();
|
||||||
VideoInterface::Init();
|
VideoInterface::Init();
|
||||||
SerialInterface::Init();
|
SerialInterface::Init();
|
||||||
CPeripheralInterface::Init();
|
CPeripheralInterface::Init();
|
||||||
Memory::Init();
|
Memory::Init();
|
||||||
DSP::Init();
|
DSP::Init();
|
||||||
DVDInterface::Init();
|
DVDInterface::Init();
|
||||||
GPFifo::Init();
|
GPFifo::Init();
|
||||||
ExpansionInterface::Init();
|
ExpansionInterface::Init();
|
||||||
CCPU::Init();
|
CCPU::Init();
|
||||||
SystemTimers::Init();
|
SystemTimers::Init();
|
||||||
|
|
||||||
WII_IPC_HLE_Interface::Init();
|
WII_IPC_HLE_Interface::Init();
|
||||||
WII_IPCInterface::Init();
|
WII_IPCInterface::Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
SystemTimers::Shutdown();
|
SystemTimers::Shutdown();
|
||||||
CCPU::Shutdown();
|
CCPU::Shutdown();
|
||||||
ExpansionInterface::Shutdown();
|
ExpansionInterface::Shutdown();
|
||||||
DVDInterface::Shutdown();
|
DVDInterface::Shutdown();
|
||||||
DSP::Shutdown();
|
DSP::Shutdown();
|
||||||
Memory::Shutdown();
|
Memory::Shutdown();
|
||||||
SerialInterface::Shutdown();
|
SerialInterface::Shutdown();
|
||||||
AudioInterface::Shutdown();
|
AudioInterface::Shutdown();
|
||||||
|
|
||||||
WII_IPC_HLE_Interface::Shutdown();
|
WII_IPC_HLE_Interface::Shutdown();
|
||||||
WII_IPCInterface::Shutdown();
|
WII_IPCInterface::Shutdown();
|
||||||
|
|
||||||
State_Shutdown();
|
State_Shutdown();
|
||||||
Thunk_Shutdown();
|
Thunk_Shutdown();
|
||||||
CoreTiming::Shutdown();
|
CoreTiming::Shutdown();
|
||||||
PPCAnalyst::Shutdown();
|
PPCAnalyst::Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
Memory::DoState(p);
|
Memory::DoState(p);
|
||||||
PixelEngine::DoState(p);
|
PixelEngine::DoState(p);
|
||||||
CommandProcessor::DoState(p);
|
CommandProcessor::DoState(p);
|
||||||
VideoInterface::DoState(p);
|
VideoInterface::DoState(p);
|
||||||
SerialInterface::DoState(p);
|
SerialInterface::DoState(p);
|
||||||
CPeripheralInterface::DoState(p);
|
CPeripheralInterface::DoState(p);
|
||||||
DSP::DoState(p);
|
DSP::DoState(p);
|
||||||
DVDInterface::DoState(p);
|
DVDInterface::DoState(p);
|
||||||
GPFifo::DoState(p);
|
GPFifo::DoState(p);
|
||||||
ExpansionInterface::DoState(p);
|
ExpansionInterface::DoState(p);
|
||||||
AudioInterface::DoState(p);
|
AudioInterface::DoState(p);
|
||||||
WII_IPCInterface::DoState(p);
|
WII_IPCInterface::DoState(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,95 +1,95 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
|
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "MemoryInterface.h"
|
#include "MemoryInterface.h"
|
||||||
|
|
||||||
namespace MemoryInterface
|
namespace MemoryInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
// internal hardware addresses
|
// internal hardware addresses
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
MEM_CHANNEL0_HI = 0x000,
|
MEM_CHANNEL0_HI = 0x000,
|
||||||
MEM_CHANNEL0_LO = 0x002,
|
MEM_CHANNEL0_LO = 0x002,
|
||||||
MEM_CHANNEL1_HI = 0x004,
|
MEM_CHANNEL1_HI = 0x004,
|
||||||
MEM_CHANNEL1_LO = 0x006,
|
MEM_CHANNEL1_LO = 0x006,
|
||||||
MEM_CHANNEL2_HI = 0x008,
|
MEM_CHANNEL2_HI = 0x008,
|
||||||
MEM_CHANNEL2_LO = 0x00A,
|
MEM_CHANNEL2_LO = 0x00A,
|
||||||
MEM_CHANNEL3_HI = 0x00C,
|
MEM_CHANNEL3_HI = 0x00C,
|
||||||
MEM_CHANNEL3_LO = 0x00E,
|
MEM_CHANNEL3_LO = 0x00E,
|
||||||
MEM_CHANNEL_CTRL = 0x010
|
MEM_CHANNEL_CTRL = 0x010
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MIMemStruct
|
struct MIMemStruct
|
||||||
{
|
{
|
||||||
u32 Channel0_Addr;
|
u32 Channel0_Addr;
|
||||||
u32 Channel1_Addr;
|
u32 Channel1_Addr;
|
||||||
u32 Channel2_Addr;
|
u32 Channel2_Addr;
|
||||||
u32 Channel3_Addr;
|
u32 Channel3_Addr;
|
||||||
u32 Channel_Ctrl;
|
u32 Channel_Ctrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
static MIMemStruct miMem;
|
static MIMemStruct miMem;
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
p.Do(miMem);
|
p.Do(miMem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Read16(u16& _uReturnValue, const u32 _iAddress)
|
void Read16(u16& _uReturnValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
//0x30 -> 0x5a : gp memory metrics
|
//0x30 -> 0x5a : gp memory metrics
|
||||||
LOG(MEMMAP, "(r16) 0x%04x @ 0x%08x", 0, _iAddress);
|
LOG(MEMMAP, "(r16) 0x%04x @ 0x%08x", 0, _iAddress);
|
||||||
_uReturnValue = 0;
|
_uReturnValue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Read32(u32& _uReturnValue, const u32 _iAddress)
|
void Read32(u32& _uReturnValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
LOG(MEMMAP, "(r32) 0x%08x @ 0x%08x", 0, _iAddress);
|
LOG(MEMMAP, "(r32) 0x%08x @ 0x%08x", 0, _iAddress);
|
||||||
_uReturnValue = 0;
|
_uReturnValue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write32(const u32 _iValue, const u32 _iAddress)
|
void Write32(const u32 _iValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
LOG(MEMMAP, "(w32) 0x%08x @ 0x%08x", _iValue, _iAddress);
|
LOG(MEMMAP, "(w32) 0x%08x @ 0x%08x", _iValue, _iAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO : check
|
//TODO : check
|
||||||
void Write16(const u16 _iValue, const u32 _iAddress)
|
void Write16(const u16 _iValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
LOG(MEMMAP, "(w16) 0x%04x @ 0x%08x", _iValue, _iAddress);
|
LOG(MEMMAP, "(w16) 0x%04x @ 0x%08x", _iValue, _iAddress);
|
||||||
switch(_iAddress & 0xFFF)
|
switch(_iAddress & 0xFFF)
|
||||||
{
|
{
|
||||||
case MEM_CHANNEL0_HI: miMem.Channel0_Addr = (miMem.Channel0_Addr & 0xFFFF) | (_iValue<<16); return;
|
case MEM_CHANNEL0_HI: miMem.Channel0_Addr = (miMem.Channel0_Addr & 0xFFFF) | (_iValue<<16); return;
|
||||||
case MEM_CHANNEL0_LO: miMem.Channel0_Addr = (miMem.Channel0_Addr & 0xFFFF0000) | (_iValue); return;
|
case MEM_CHANNEL0_LO: miMem.Channel0_Addr = (miMem.Channel0_Addr & 0xFFFF0000) | (_iValue); return;
|
||||||
case MEM_CHANNEL1_HI: miMem.Channel1_Addr = (miMem.Channel1_Addr & 0xFFFF) | (_iValue<<16); return;
|
case MEM_CHANNEL1_HI: miMem.Channel1_Addr = (miMem.Channel1_Addr & 0xFFFF) | (_iValue<<16); return;
|
||||||
case MEM_CHANNEL1_LO: miMem.Channel1_Addr = (miMem.Channel1_Addr & 0xFFFF0000) | (_iValue); return;
|
case MEM_CHANNEL1_LO: miMem.Channel1_Addr = (miMem.Channel1_Addr & 0xFFFF0000) | (_iValue); return;
|
||||||
case MEM_CHANNEL2_HI: miMem.Channel2_Addr = (miMem.Channel2_Addr & 0xFFFF) | (_iValue<<16); return;
|
case MEM_CHANNEL2_HI: miMem.Channel2_Addr = (miMem.Channel2_Addr & 0xFFFF) | (_iValue<<16); return;
|
||||||
case MEM_CHANNEL2_LO: miMem.Channel2_Addr = (miMem.Channel2_Addr & 0xFFFF0000) | (_iValue); return;
|
case MEM_CHANNEL2_LO: miMem.Channel2_Addr = (miMem.Channel2_Addr & 0xFFFF0000) | (_iValue); return;
|
||||||
case MEM_CHANNEL3_HI: miMem.Channel3_Addr = (miMem.Channel3_Addr & 0xFFFF) | (_iValue<<16); return;
|
case MEM_CHANNEL3_HI: miMem.Channel3_Addr = (miMem.Channel3_Addr & 0xFFFF) | (_iValue<<16); return;
|
||||||
case MEM_CHANNEL3_LO: miMem.Channel3_Addr = (miMem.Channel3_Addr & 0xFFFF0000) | (_iValue); return;
|
case MEM_CHANNEL3_LO: miMem.Channel3_Addr = (miMem.Channel3_Addr & 0xFFFF0000) | (_iValue); return;
|
||||||
case MEM_CHANNEL_CTRL: miMem.Channel_Ctrl = _iValue; return;
|
case MEM_CHANNEL_CTRL: miMem.Channel_Ctrl = _iValue; return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace MemoryInterface
|
} // end of namespace MemoryInterface
|
||||||
|
|
||||||
|
|
|
@ -1,232 +1,232 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
|
|
||||||
#include "../HW/CPU.h"
|
#include "../HW/CPU.h"
|
||||||
#include "PeripheralInterface.h"
|
#include "PeripheralInterface.h"
|
||||||
#include "GPFifo.h"
|
#include "GPFifo.h"
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
u32 volatile CPeripheralInterface::m_InterruptMask;
|
u32 volatile CPeripheralInterface::m_InterruptMask;
|
||||||
u32 volatile CPeripheralInterface::m_InterruptCause;
|
u32 volatile CPeripheralInterface::m_InterruptCause;
|
||||||
|
|
||||||
// addresses for CPU fifo accesses
|
// addresses for CPU fifo accesses
|
||||||
u32 CPeripheralInterface::Fifo_CPUBase;
|
u32 CPeripheralInterface::Fifo_CPUBase;
|
||||||
u32 CPeripheralInterface::Fifo_CPUEnd;
|
u32 CPeripheralInterface::Fifo_CPUEnd;
|
||||||
u32 CPeripheralInterface::Fifo_CPUWritePointer;
|
u32 CPeripheralInterface::Fifo_CPUWritePointer;
|
||||||
|
|
||||||
void CPeripheralInterface::DoState(PointerWrap &p)
|
void CPeripheralInterface::DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
p.Do(m_InterruptMask);
|
p.Do(m_InterruptMask);
|
||||||
p.Do(m_InterruptCause);
|
p.Do(m_InterruptCause);
|
||||||
p.Do(Fifo_CPUBase);
|
p.Do(Fifo_CPUBase);
|
||||||
p.Do(Fifo_CPUEnd);
|
p.Do(Fifo_CPUEnd);
|
||||||
p.Do(Fifo_CPUWritePointer);
|
p.Do(Fifo_CPUWritePointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPeripheralInterface::Init()
|
void CPeripheralInterface::Init()
|
||||||
{
|
{
|
||||||
m_InterruptMask = 0;
|
m_InterruptMask = 0;
|
||||||
m_InterruptCause = 0;
|
m_InterruptCause = 0;
|
||||||
|
|
||||||
Fifo_CPUBase = 0;
|
Fifo_CPUBase = 0;
|
||||||
Fifo_CPUEnd = 0;
|
Fifo_CPUEnd = 0;
|
||||||
Fifo_CPUWritePointer = 0;
|
Fifo_CPUWritePointer = 0;
|
||||||
|
|
||||||
m_InterruptCause |= INT_CAUSE_RST_BUTTON; // Reset button state
|
m_InterruptCause |= INT_CAUSE_RST_BUTTON; // Reset button state
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPeripheralInterface::Read32(u32& _uReturnValue, const u32 _iAddress)
|
void CPeripheralInterface::Read32(u32& _uReturnValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
//LOG(PERIPHERALINTERFACE, "(r32) 0x%08x", _iAddress);
|
//LOG(PERIPHERALINTERFACE, "(r32) 0x%08x", _iAddress);
|
||||||
|
|
||||||
switch(_iAddress & 0xFFF)
|
switch(_iAddress & 0xFFF)
|
||||||
{
|
{
|
||||||
case PI_INTERRUPT_CAUSE:
|
case PI_INTERRUPT_CAUSE:
|
||||||
_uReturnValue = m_InterruptCause;
|
_uReturnValue = m_InterruptCause;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case PI_INTERRUPT_MASK:
|
case PI_INTERRUPT_MASK:
|
||||||
_uReturnValue = m_InterruptMask;
|
_uReturnValue = m_InterruptMask;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case PI_FIFO_BASE:
|
case PI_FIFO_BASE:
|
||||||
LOG(PERIPHERALINTERFACE,"read cpu fifo base, value = %08x",Fifo_CPUBase);
|
LOG(PERIPHERALINTERFACE,"read cpu fifo base, value = %08x",Fifo_CPUBase);
|
||||||
_uReturnValue = Fifo_CPUBase;
|
_uReturnValue = Fifo_CPUBase;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case PI_FIFO_END:
|
case PI_FIFO_END:
|
||||||
LOG(PERIPHERALINTERFACE,"read cpu fifo end, value = %08x",Fifo_CPUEnd);
|
LOG(PERIPHERALINTERFACE,"read cpu fifo end, value = %08x",Fifo_CPUEnd);
|
||||||
_uReturnValue = Fifo_CPUEnd;
|
_uReturnValue = Fifo_CPUEnd;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case PI_FIFO_WPTR:
|
case PI_FIFO_WPTR:
|
||||||
LOGV(PERIPHERALINTERFACE, 3, "read writepointer, value = %08x",Fifo_CPUWritePointer);
|
LOGV(PERIPHERALINTERFACE, 3, "read writepointer, value = %08x",Fifo_CPUWritePointer);
|
||||||
_uReturnValue = Fifo_CPUWritePointer; //really writes in 32-byte chunks
|
_uReturnValue = Fifo_CPUWritePointer; //really writes in 32-byte chunks
|
||||||
|
|
||||||
// Monk's gcube does some crazy align trickery here.
|
// Monk's gcube does some crazy align trickery here.
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case PI_RESET_CODE:
|
case PI_RESET_CODE:
|
||||||
_uReturnValue = 0x80000000;
|
_uReturnValue = 0x80000000;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case PI_MB_REV:
|
case PI_MB_REV:
|
||||||
_uReturnValue = 0x20000000; // HW2 production board
|
_uReturnValue = 0x20000000; // HW2 production board
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG(PERIPHERALINTERFACE,"!!!!Unknown write!!!! 0x%08x", _iAddress);
|
LOG(PERIPHERALINTERFACE,"!!!!Unknown write!!!! 0x%08x", _iAddress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_uReturnValue = 0xAFFE0000;
|
_uReturnValue = 0xAFFE0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPeripheralInterface::Write32(const u32 _uValue, const u32 _iAddress)
|
void CPeripheralInterface::Write32(const u32 _uValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
LOG(PERIPHERALINTERFACE, "(w32) 0x%08x @ 0x%08x", _uValue, _iAddress);
|
LOG(PERIPHERALINTERFACE, "(w32) 0x%08x @ 0x%08x", _uValue, _iAddress);
|
||||||
switch(_iAddress & 0xFFF)
|
switch(_iAddress & 0xFFF)
|
||||||
{
|
{
|
||||||
case PI_INTERRUPT_CAUSE:
|
case PI_INTERRUPT_CAUSE:
|
||||||
m_InterruptCause &= ~_uValue; //writes turns them off
|
m_InterruptCause &= ~_uValue; //writes turns them off
|
||||||
UpdateException();
|
UpdateException();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case PI_INTERRUPT_MASK:
|
case PI_INTERRUPT_MASK:
|
||||||
m_InterruptMask = _uValue;
|
m_InterruptMask = _uValue;
|
||||||
LOG(PERIPHERALINTERFACE,"New Interrupt mask: %08x",m_InterruptMask);
|
LOG(PERIPHERALINTERFACE,"New Interrupt mask: %08x",m_InterruptMask);
|
||||||
UpdateException();
|
UpdateException();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case PI_FIFO_BASE:
|
case PI_FIFO_BASE:
|
||||||
Fifo_CPUBase = _uValue & 0xFFFFFFE0;
|
Fifo_CPUBase = _uValue & 0xFFFFFFE0;
|
||||||
LOG(PERIPHERALINTERFACE,"Fifo base = %08x", _uValue);
|
LOG(PERIPHERALINTERFACE,"Fifo base = %08x", _uValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PI_FIFO_END:
|
case PI_FIFO_END:
|
||||||
Fifo_CPUEnd = _uValue & 0xFFFFFFE0;
|
Fifo_CPUEnd = _uValue & 0xFFFFFFE0;
|
||||||
LOG(PERIPHERALINTERFACE,"Fifo end = %08x", _uValue);
|
LOG(PERIPHERALINTERFACE,"Fifo end = %08x", _uValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PI_FIFO_WPTR:
|
case PI_FIFO_WPTR:
|
||||||
Fifo_CPUWritePointer = _uValue & 0xFFFFFFE0;
|
Fifo_CPUWritePointer = _uValue & 0xFFFFFFE0;
|
||||||
LOG(PERIPHERALINTERFACE,"Fifo writeptr = %08x", _uValue);
|
LOG(PERIPHERALINTERFACE,"Fifo writeptr = %08x", _uValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PI_FIFO_RESET:
|
case PI_FIFO_RESET:
|
||||||
// Fifo_CPUWritePointer = Fifo_CPUBase; ??
|
// Fifo_CPUWritePointer = Fifo_CPUBase; ??
|
||||||
// PanicAlert("Unknown write to PI_FIFO_RESET (%08x)", _uValue);
|
// PanicAlert("Unknown write to PI_FIFO_RESET (%08x)", _uValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PI_RESET_CODE:
|
case PI_RESET_CODE:
|
||||||
{
|
{
|
||||||
LOG(PERIPHERALINTERFACE,"PI Reset = %08x ???", _uValue);
|
LOG(PERIPHERALINTERFACE,"PI Reset = %08x ???", _uValue);
|
||||||
|
|
||||||
if ((_uValue != 0x80000001) && (_uValue != 0x80000005)) // DVDLowReset
|
if ((_uValue != 0x80000001) && (_uValue != 0x80000005)) // DVDLowReset
|
||||||
{
|
{
|
||||||
switch (_uValue) {
|
switch (_uValue) {
|
||||||
case 3:
|
case 3:
|
||||||
PanicAlert("The game wants to go to memory card manager. BIOS is being HLE:d - so we can't do that.\n");
|
PanicAlert("The game wants to go to memory card manager. BIOS is being HLE:d - so we can't do that.\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
TCHAR szTemp[256];
|
TCHAR szTemp[256];
|
||||||
sprintf(szTemp, "The game wants to reset the machine. PI_RESET_CODE: (%08x)", _uValue);
|
sprintf(szTemp, "The game wants to reset the machine. PI_RESET_CODE: (%08x)", _uValue);
|
||||||
PanicAlert(szTemp);
|
PanicAlert(szTemp);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG(PERIPHERALINTERFACE,"!!!!Unknown PI write!!!! 0x%08x", _iAddress);
|
LOG(PERIPHERALINTERFACE,"!!!!Unknown PI write!!!! 0x%08x", _iAddress);
|
||||||
PanicAlert("Unknown write to PI: %08x", _iAddress);
|
PanicAlert("Unknown write to PI: %08x", _iAddress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPeripheralInterface::UpdateException()
|
void CPeripheralInterface::UpdateException()
|
||||||
{
|
{
|
||||||
if ((m_InterruptCause & m_InterruptMask) != 0)
|
if ((m_InterruptCause & m_InterruptMask) != 0)
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_EXTERNAL_INT;
|
PowerPC::ppcState.Exceptions |= EXCEPTION_EXTERNAL_INT;
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
|
PowerPC::ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CPeripheralInterface::Debug_GetInterruptName(InterruptCause _causemask)
|
const char *CPeripheralInterface::Debug_GetInterruptName(InterruptCause _causemask)
|
||||||
{
|
{
|
||||||
switch (_causemask)
|
switch (_causemask)
|
||||||
{
|
{
|
||||||
case INT_CAUSE_ERROR: return "INT_CAUSE_ERROR";
|
case INT_CAUSE_ERROR: return "INT_CAUSE_ERROR";
|
||||||
case INT_CAUSE_DI: return "INT_CAUSE_DI";
|
case INT_CAUSE_DI: return "INT_CAUSE_DI";
|
||||||
case INT_CAUSE_RSW: return "INT_CAUSE_RSW";
|
case INT_CAUSE_RSW: return "INT_CAUSE_RSW";
|
||||||
case INT_CAUSE_SI: return "INT_CAUSE_SI";
|
case INT_CAUSE_SI: return "INT_CAUSE_SI";
|
||||||
case INT_CAUSE_EXI: return "INT_CAUSE_EXI";
|
case INT_CAUSE_EXI: return "INT_CAUSE_EXI";
|
||||||
case INT_CAUSE_AUDIO: return "INT_CAUSE_AUDIO";
|
case INT_CAUSE_AUDIO: return "INT_CAUSE_AUDIO";
|
||||||
case INT_CAUSE_DSP: return "INT_CAUSE_DSP";
|
case INT_CAUSE_DSP: return "INT_CAUSE_DSP";
|
||||||
case INT_CAUSE_MEMORY: return "INT_CAUSE_MEMORY";
|
case INT_CAUSE_MEMORY: return "INT_CAUSE_MEMORY";
|
||||||
case INT_CAUSE_VI: return "INT_CAUSE_VI";
|
case INT_CAUSE_VI: return "INT_CAUSE_VI";
|
||||||
case INT_CAUSE_PE_TOKEN: return "INT_CAUSE_PE_TOKEN";
|
case INT_CAUSE_PE_TOKEN: return "INT_CAUSE_PE_TOKEN";
|
||||||
case INT_CAUSE_PE_FINISH: return "INT_CAUSE_PE_FINISH";
|
case INT_CAUSE_PE_FINISH: return "INT_CAUSE_PE_FINISH";
|
||||||
case INT_CAUSE_CP: return "INT_CAUSE_CP";
|
case INT_CAUSE_CP: return "INT_CAUSE_CP";
|
||||||
case INT_CAUSE_DEBUG: return "INT_CAUSE_DEBUG";
|
case INT_CAUSE_DEBUG: return "INT_CAUSE_DEBUG";
|
||||||
case INT_CAUSE_WII_IPC: return "INT_CAUSE_WII_IPC";
|
case INT_CAUSE_WII_IPC: return "INT_CAUSE_WII_IPC";
|
||||||
case INT_CAUSE_HSP: return "INT_CAUSE_HSP";
|
case INT_CAUSE_HSP: return "INT_CAUSE_HSP";
|
||||||
case INT_CAUSE_RST_BUTTON: return "INT_CAUSE_RST_BUTTON";
|
case INT_CAUSE_RST_BUTTON: return "INT_CAUSE_RST_BUTTON";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "!!! ERROR-unknown Interrupt !!!";
|
return "!!! ERROR-unknown Interrupt !!!";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPeripheralInterface::SetInterrupt(InterruptCause _causemask, bool _bSet)
|
void CPeripheralInterface::SetInterrupt(InterruptCause _causemask, bool _bSet)
|
||||||
{
|
{
|
||||||
//TODO(ector): add sanity check that current thread id is cpu thread
|
//TODO(ector): add sanity check that current thread id is cpu thread
|
||||||
|
|
||||||
if (_bSet && !(m_InterruptCause & (u32)_causemask))
|
if (_bSet && !(m_InterruptCause & (u32)_causemask))
|
||||||
{
|
{
|
||||||
LOGV(PERIPHERALINTERFACE, 2, "Setting Interrupt %s (%s)",Debug_GetInterruptName(_causemask), "set");
|
LOGV(PERIPHERALINTERFACE, 2, "Setting Interrupt %s (%s)",Debug_GetInterruptName(_causemask), "set");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_bSet && (m_InterruptCause & (u32)_causemask))
|
if (!_bSet && (m_InterruptCause & (u32)_causemask))
|
||||||
{
|
{
|
||||||
LOGV(PERIPHERALINTERFACE, 2, "Setting Interrupt %s (%s)",Debug_GetInterruptName(_causemask), "clear");
|
LOGV(PERIPHERALINTERFACE, 2, "Setting Interrupt %s (%s)",Debug_GetInterruptName(_causemask), "clear");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_bSet)
|
if (_bSet)
|
||||||
m_InterruptCause |= (u32)_causemask;
|
m_InterruptCause |= (u32)_causemask;
|
||||||
else
|
else
|
||||||
m_InterruptCause &= ~(u32)_causemask; // is there any reason to have this possibility?
|
m_InterruptCause &= ~(u32)_causemask; // is there any reason to have this possibility?
|
||||||
// F|RES: i think the hw devices reset the interrupt in the PI to 0
|
// F|RES: i think the hw devices reset the interrupt in the PI to 0
|
||||||
// if the interrupt cause is eliminated. that isnt done by software (afaik)
|
// if the interrupt cause is eliminated. that isnt done by software (afaik)
|
||||||
UpdateException();
|
UpdateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPeripheralInterface::SetResetButton(bool _bSet)
|
void CPeripheralInterface::SetResetButton(bool _bSet)
|
||||||
{
|
{
|
||||||
if (_bSet)
|
if (_bSet)
|
||||||
m_InterruptCause &= ~INT_CAUSE_RST_BUTTON;
|
m_InterruptCause &= ~INT_CAUSE_RST_BUTTON;
|
||||||
else
|
else
|
||||||
m_InterruptCause |= INT_CAUSE_RST_BUTTON;
|
m_InterruptCause |= INT_CAUSE_RST_BUTTON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,219 +1,219 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
|
|
||||||
#include "PixelEngine.h"
|
#include "PixelEngine.h"
|
||||||
|
|
||||||
#include "../CoreTiming.h"
|
#include "../CoreTiming.h"
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "PeripheralInterface.h"
|
#include "PeripheralInterface.h"
|
||||||
#include "CommandProcessor.h"
|
#include "CommandProcessor.h"
|
||||||
#include "CPU.h"
|
#include "CPU.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
|
|
||||||
namespace PixelEngine
|
namespace PixelEngine
|
||||||
{
|
{
|
||||||
|
|
||||||
// internal hardware addresses
|
// internal hardware addresses
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
CTRL_REGISTER = 0x00a,
|
CTRL_REGISTER = 0x00a,
|
||||||
TOKEN_REG = 0x00e,
|
TOKEN_REG = 0x00e,
|
||||||
};
|
};
|
||||||
|
|
||||||
// fifo Control Register
|
// fifo Control Register
|
||||||
union UPECtrlReg
|
union UPECtrlReg
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned PETokenEnable : 1;
|
unsigned PETokenEnable : 1;
|
||||||
unsigned PEFinishEnable : 1;
|
unsigned PEFinishEnable : 1;
|
||||||
unsigned PEToken : 1; // write only
|
unsigned PEToken : 1; // write only
|
||||||
unsigned PEFinish : 1; // write only
|
unsigned PEFinish : 1; // write only
|
||||||
unsigned : 12;
|
unsigned : 12;
|
||||||
};
|
};
|
||||||
u16 Hex;
|
u16 Hex;
|
||||||
UPECtrlReg() {Hex = 0; }
|
UPECtrlReg() {Hex = 0; }
|
||||||
UPECtrlReg(u16 _hex) {Hex = _hex; }
|
UPECtrlReg(u16 _hex) {Hex = _hex; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
static UPECtrlReg g_ctrlReg;
|
static UPECtrlReg g_ctrlReg;
|
||||||
|
|
||||||
static bool g_bSignalTokenInterrupt;
|
static bool g_bSignalTokenInterrupt;
|
||||||
static bool g_bSignalFinishInterrupt;
|
static bool g_bSignalFinishInterrupt;
|
||||||
|
|
||||||
int et_SetTokenOnMainThread;
|
int et_SetTokenOnMainThread;
|
||||||
int et_SetFinishOnMainThread;
|
int et_SetFinishOnMainThread;
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
p.Do(g_ctrlReg);
|
p.Do(g_ctrlReg);
|
||||||
p.Do(CommandProcessor::fifo.PEToken);
|
p.Do(CommandProcessor::fifo.PEToken);
|
||||||
p.Do(g_bSignalTokenInterrupt);
|
p.Do(g_bSignalTokenInterrupt);
|
||||||
p.Do(g_bSignalFinishInterrupt);
|
p.Do(g_bSignalFinishInterrupt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateInterrupts();
|
void UpdateInterrupts();
|
||||||
|
|
||||||
void SetToken_OnMainThread(u64 userdata, int cyclesLate);
|
void SetToken_OnMainThread(u64 userdata, int cyclesLate);
|
||||||
void SetFinish_OnMainThread(u64 userdata, int cyclesLate);
|
void SetFinish_OnMainThread(u64 userdata, int cyclesLate);
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
g_ctrlReg.Hex = 0;
|
g_ctrlReg.Hex = 0;
|
||||||
|
|
||||||
et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread);
|
et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread);
|
||||||
et_SetFinishOnMainThread = CoreTiming::RegisterEvent("SetFinish", SetFinish_OnMainThread);
|
et_SetFinishOnMainThread = CoreTiming::RegisterEvent("SetFinish", SetFinish_OnMainThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Read16(u16& _uReturnValue, const u32 _iAddress)
|
void Read16(u16& _uReturnValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
LOGV(PIXELENGINE, 3, "(r16): 0x%08x", _iAddress);
|
LOGV(PIXELENGINE, 3, "(r16): 0x%08x", _iAddress);
|
||||||
|
|
||||||
switch (_iAddress & 0xFFF)
|
switch (_iAddress & 0xFFF)
|
||||||
{
|
{
|
||||||
case CTRL_REGISTER:
|
case CTRL_REGISTER:
|
||||||
_uReturnValue = g_ctrlReg.Hex;
|
_uReturnValue = g_ctrlReg.Hex;
|
||||||
LOG(PIXELENGINE,"\t CTRL_REGISTER : %04x", _uReturnValue);
|
LOG(PIXELENGINE,"\t CTRL_REGISTER : %04x", _uReturnValue);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case TOKEN_REG:
|
case TOKEN_REG:
|
||||||
_uReturnValue = CommandProcessor::fifo.PEToken;
|
_uReturnValue = CommandProcessor::fifo.PEToken;
|
||||||
LOG(PIXELENGINE,"\t TOKEN_REG : %04x", _uReturnValue);
|
LOG(PIXELENGINE,"\t TOKEN_REG : %04x", _uReturnValue);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG(PIXELENGINE,"(unknown)");
|
LOG(PIXELENGINE,"(unknown)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_uReturnValue = 0x001;
|
_uReturnValue = 0x001;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write32(const u32 _iValue, const u32 _iAddress)
|
void Write32(const u32 _iValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
LOGV(PIXELENGINE, 2, "(w32): 0x%08x @ 0x%08x",_iValue,_iAddress);
|
LOGV(PIXELENGINE, 2, "(w32): 0x%08x @ 0x%08x",_iValue,_iAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write16(const u16 _iValue, const u32 _iAddress)
|
void Write16(const u16 _iValue, const u32 _iAddress)
|
||||||
{
|
{
|
||||||
LOGV(PIXELENGINE, 3, "(w16): 0x%04x @ 0x%08x",_iValue,_iAddress);
|
LOGV(PIXELENGINE, 3, "(w16): 0x%04x @ 0x%08x",_iValue,_iAddress);
|
||||||
|
|
||||||
switch(_iAddress & 0xFFF)
|
switch(_iAddress & 0xFFF)
|
||||||
{
|
{
|
||||||
case CTRL_REGISTER:
|
case CTRL_REGISTER:
|
||||||
{
|
{
|
||||||
UPECtrlReg tmpCtrl(_iValue);
|
UPECtrlReg tmpCtrl(_iValue);
|
||||||
|
|
||||||
if (tmpCtrl.PEToken) g_bSignalTokenInterrupt = false;
|
if (tmpCtrl.PEToken) g_bSignalTokenInterrupt = false;
|
||||||
if (tmpCtrl.PEFinish) g_bSignalFinishInterrupt = false;
|
if (tmpCtrl.PEFinish) g_bSignalFinishInterrupt = false;
|
||||||
|
|
||||||
g_ctrlReg.PETokenEnable = tmpCtrl.PETokenEnable;
|
g_ctrlReg.PETokenEnable = tmpCtrl.PETokenEnable;
|
||||||
g_ctrlReg.PEFinishEnable = tmpCtrl.PEFinishEnable;
|
g_ctrlReg.PEFinishEnable = tmpCtrl.PEFinishEnable;
|
||||||
g_ctrlReg.PEToken = 0; // this flag is write only
|
g_ctrlReg.PEToken = 0; // this flag is write only
|
||||||
g_ctrlReg.PEFinish = 0; // this flag is write only
|
g_ctrlReg.PEFinish = 0; // this flag is write only
|
||||||
|
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOKEN_REG:
|
case TOKEN_REG:
|
||||||
//LOG(PIXELENGINE,"WEIRD: program wrote token: %i",_iValue);
|
//LOG(PIXELENGINE,"WEIRD: program wrote token: %i",_iValue);
|
||||||
PanicAlert("PIXELENGINE : (w16) WTF? program wrote token: %i",_iValue);
|
PanicAlert("PIXELENGINE : (w16) WTF? program wrote token: %i",_iValue);
|
||||||
//only the gx pipeline is supposed to be able to write here
|
//only the gx pipeline is supposed to be able to write here
|
||||||
//g_token = _iValue;
|
//g_token = _iValue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AllowIdleSkipping()
|
bool AllowIdleSkipping()
|
||||||
{
|
{
|
||||||
return !Core::g_CoreStartupParameter.bUseDualCore || (!g_ctrlReg.PETokenEnable && !g_ctrlReg.PEFinishEnable);
|
return !Core::g_CoreStartupParameter.bUseDualCore || (!g_ctrlReg.PETokenEnable && !g_ctrlReg.PEFinishEnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateInterrupts()
|
void UpdateInterrupts()
|
||||||
{
|
{
|
||||||
// check if there is a token-interrupt
|
// check if there is a token-interrupt
|
||||||
if (g_bSignalTokenInterrupt & g_ctrlReg.PETokenEnable)
|
if (g_bSignalTokenInterrupt & g_ctrlReg.PETokenEnable)
|
||||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_TOKEN, true);
|
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_TOKEN, true);
|
||||||
else
|
else
|
||||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_TOKEN, false);
|
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_TOKEN, false);
|
||||||
|
|
||||||
// check if there is a finish-interrupt
|
// check if there is a finish-interrupt
|
||||||
if (g_bSignalFinishInterrupt & g_ctrlReg.PEFinishEnable)
|
if (g_bSignalFinishInterrupt & g_ctrlReg.PEFinishEnable)
|
||||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_FINISH, true);
|
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_FINISH, true);
|
||||||
else
|
else
|
||||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_FINISH, false);
|
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_FINISH, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(mb2): Refactor SetTokenINT_OnMainThread(u64 userdata, int cyclesLate).
|
// TODO(mb2): Refactor SetTokenINT_OnMainThread(u64 userdata, int cyclesLate).
|
||||||
// Think about the right order between tokenVal and tokenINT... one day maybe.
|
// Think about the right order between tokenVal and tokenINT... one day maybe.
|
||||||
// Cleanup++
|
// Cleanup++
|
||||||
|
|
||||||
// Called only if BPMEM_PE_TOKEN_INT_ID is ack by GP
|
// Called only if BPMEM_PE_TOKEN_INT_ID is ack by GP
|
||||||
void SetToken_OnMainThread(u64 userdata, int cyclesLate)
|
void SetToken_OnMainThread(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
//if (userdata >> 16)
|
//if (userdata >> 16)
|
||||||
//{
|
//{
|
||||||
g_bSignalTokenInterrupt = true;
|
g_bSignalTokenInterrupt = true;
|
||||||
//_dbg_assert_msg_(PIXELENGINE, (CommandProcessor::fifo.PEToken == (userdata&0xFFFF)), "WTF? BPMEM_PE_TOKEN_INT_ID's token != BPMEM_PE_TOKEN_ID's token" );
|
//_dbg_assert_msg_(PIXELENGINE, (CommandProcessor::fifo.PEToken == (userdata&0xFFFF)), "WTF? BPMEM_PE_TOKEN_INT_ID's token != BPMEM_PE_TOKEN_ID's token" );
|
||||||
LOGV(PIXELENGINE, 1, "VIDEO Plugin raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", CommandProcessor::fifo.PEToken);
|
LOGV(PIXELENGINE, 1, "VIDEO Plugin raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", CommandProcessor::fifo.PEToken);
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
//}
|
//}
|
||||||
//else
|
//else
|
||||||
// LOGV(PIXELENGINE, 1, "VIDEO Plugin wrote token: %i", CommandProcessor::fifo.PEToken);
|
// LOGV(PIXELENGINE, 1, "VIDEO Plugin wrote token: %i", CommandProcessor::fifo.PEToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
|
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
g_bSignalFinishInterrupt = 1;
|
g_bSignalFinishInterrupt = 1;
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetToken
|
// SetToken
|
||||||
// THIS IS EXECUTED FROM VIDEO THREAD
|
// THIS IS EXECUTED FROM VIDEO THREAD
|
||||||
void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
|
void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
|
||||||
{
|
{
|
||||||
// TODO?: set-token-value and set-token-INT could be merged since set-token-INT own the token value.
|
// TODO?: set-token-value and set-token-INT could be merged since set-token-INT own the token value.
|
||||||
if (_bSetTokenAcknowledge) // set token INT
|
if (_bSetTokenAcknowledge) // set token INT
|
||||||
{
|
{
|
||||||
CommandProcessor::IncrementGPWDToken(); // for DC watchdog hack since PEToken seems to be a frame-finish too
|
CommandProcessor::IncrementGPWDToken(); // for DC watchdog hack since PEToken seems to be a frame-finish too
|
||||||
CoreTiming::ScheduleEvent_Threadsafe(
|
CoreTiming::ScheduleEvent_Threadsafe(
|
||||||
0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16));
|
0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16));
|
||||||
}
|
}
|
||||||
else // set token value
|
else // set token value
|
||||||
{
|
{
|
||||||
// we do it directly from videoThread because of
|
// we do it directly from videoThread because of
|
||||||
// Super Monkey Ball Advance
|
// Super Monkey Ball Advance
|
||||||
Common::SyncInterlockedExchange((LONG*)&CommandProcessor::fifo.PEToken, _token);
|
Common::SyncInterlockedExchange((LONG*)&CommandProcessor::fifo.PEToken, _token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFinish
|
// SetFinish
|
||||||
// THIS IS EXECUTED FROM VIDEO THREAD
|
// THIS IS EXECUTED FROM VIDEO THREAD
|
||||||
void SetFinish()
|
void SetFinish()
|
||||||
{
|
{
|
||||||
CommandProcessor::IncrementGPWDToken(); // for DC watchdog hack
|
CommandProcessor::IncrementGPWDToken(); // for DC watchdog hack
|
||||||
CoreTiming::ScheduleEvent_Threadsafe(
|
CoreTiming::ScheduleEvent_Threadsafe(
|
||||||
0, et_SetFinishOnMainThread);
|
0, et_SetFinishOnMainThread);
|
||||||
LOGV(PIXELENGINE, 2, "VIDEO Set Finish");
|
LOGV(PIXELENGINE, 2, "VIDEO Set Finish");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace PixelEngine
|
} // end of namespace PixelEngine
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,238 +1,238 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "SerialInterface_Devices.h"
|
#include "SerialInterface_Devices.h"
|
||||||
|
|
||||||
#include "EXI_Device.h"
|
#include "EXI_Device.h"
|
||||||
#include "EXI_DeviceMic.h"
|
#include "EXI_DeviceMic.h"
|
||||||
|
|
||||||
#include "../Plugins/Plugin_PAD.h"
|
#include "../Plugins/Plugin_PAD.h"
|
||||||
|
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "CPU.h"
|
#include "CPU.h"
|
||||||
|
|
||||||
#define SI_TYPE_GC 0x08000000u
|
#define SI_TYPE_GC 0x08000000u
|
||||||
|
|
||||||
#define SI_GC_STANDARD 0x01000000u // dolphin standard controller
|
#define SI_GC_STANDARD 0x01000000u // dolphin standard controller
|
||||||
#define SI_GC_NOMOTOR 0x20000000u // no rumble motor
|
#define SI_GC_NOMOTOR 0x20000000u // no rumble motor
|
||||||
|
|
||||||
#define SI_GC_KEYBOARD (SI_TYPE_GC | 0x00200000)
|
#define SI_GC_KEYBOARD (SI_TYPE_GC | 0x00200000)
|
||||||
#define SI_GC_CONTROLLER (SI_TYPE_GC | SI_GC_STANDARD)
|
#define SI_GC_CONTROLLER (SI_TYPE_GC | SI_GC_STANDARD)
|
||||||
|
|
||||||
#define SI_MAX_COMCSR_INLNGTH 128
|
#define SI_MAX_COMCSR_INLNGTH 128
|
||||||
#define SI_MAX_COMCSR_OUTLNGTH 128
|
#define SI_MAX_COMCSR_OUTLNGTH 128
|
||||||
|
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
// --- base class ---
|
// --- base class ---
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
|
|
||||||
int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength)
|
int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
LOG(SERIALINTERFACE, "Send Data Device(%i) - Length(%i) ", ISIDevice::m_iDeviceNumber,_iLength);
|
LOG(SERIALINTERFACE, "Send Data Device(%i) - Length(%i) ", ISIDevice::m_iDeviceNumber,_iLength);
|
||||||
|
|
||||||
char szTemp[256] = "";
|
char szTemp[256] = "";
|
||||||
int num = 0;
|
int num = 0;
|
||||||
while(num < _iLength)
|
while(num < _iLength)
|
||||||
{
|
{
|
||||||
char szTemp2[128] = "";
|
char szTemp2[128] = "";
|
||||||
sprintf(szTemp2, "0x%02x ", _pBuffer[num^3]);
|
sprintf(szTemp2, "0x%02x ", _pBuffer[num^3]);
|
||||||
strcat(szTemp, szTemp2);
|
strcat(szTemp, szTemp2);
|
||||||
num++;
|
num++;
|
||||||
|
|
||||||
if ((num % 8) == 0)
|
if ((num % 8) == 0)
|
||||||
{
|
{
|
||||||
LOG(SERIALINTERFACE, szTemp);
|
LOG(SERIALINTERFACE, szTemp);
|
||||||
szTemp[0] = '\0';
|
szTemp[0] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG(SERIALINTERFACE, szTemp);
|
LOG(SERIALINTERFACE, szTemp);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
// --- standard gamecube controller ---
|
// --- standard gamecube controller ---
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
|
|
||||||
CSIDevice_GCController::CSIDevice_GCController(int _iDeviceNumber) :
|
CSIDevice_GCController::CSIDevice_GCController(int _iDeviceNumber) :
|
||||||
ISIDevice(_iDeviceNumber)
|
ISIDevice(_iDeviceNumber)
|
||||||
{
|
{
|
||||||
memset(&m_origin, 0, sizeof(SOrigin));
|
memset(&m_origin, 0, sizeof(SOrigin));
|
||||||
|
|
||||||
m_origin.uCommand = 0x41;
|
m_origin.uCommand = 0x41;
|
||||||
m_origin.uOriginStickX = 0x80;
|
m_origin.uOriginStickX = 0x80;
|
||||||
m_origin.uOriginStickY = 0x80;
|
m_origin.uOriginStickY = 0x80;
|
||||||
m_origin.uSubStickStickX = 0x80;
|
m_origin.uSubStickStickX = 0x80;
|
||||||
m_origin.uSubStickStickY = 0x80;
|
m_origin.uSubStickStickY = 0x80;
|
||||||
m_origin.uTrigger_L = 0x1F;
|
m_origin.uTrigger_L = 0x1F;
|
||||||
m_origin.uTrigger_R = 0x1F;
|
m_origin.uTrigger_R = 0x1F;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength)
|
int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength)
|
||||||
{
|
{
|
||||||
// for debug logging only
|
// for debug logging only
|
||||||
ISIDevice::RunBuffer(_pBuffer, _iLength);
|
ISIDevice::RunBuffer(_pBuffer, _iLength);
|
||||||
|
|
||||||
int iPosition = 0;
|
int iPosition = 0;
|
||||||
while(iPosition < _iLength)
|
while(iPosition < _iLength)
|
||||||
{
|
{
|
||||||
// read the command
|
// read the command
|
||||||
EBufferCommands command = static_cast<EBufferCommands>(_pBuffer[iPosition ^ 3]);
|
EBufferCommands command = static_cast<EBufferCommands>(_pBuffer[iPosition ^ 3]);
|
||||||
iPosition++;
|
iPosition++;
|
||||||
|
|
||||||
// handle it
|
// handle it
|
||||||
switch(command)
|
switch(command)
|
||||||
{
|
{
|
||||||
case CMD_RESET:
|
case CMD_RESET:
|
||||||
{
|
{
|
||||||
*(u32*)&_pBuffer[0] = SI_GC_CONTROLLER; // | SI_GC_NOMOTOR;
|
*(u32*)&_pBuffer[0] = SI_GC_CONTROLLER; // | SI_GC_NOMOTOR;
|
||||||
iPosition = _iLength; // break the while loop
|
iPosition = _iLength; // break the while loop
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_ORIGIN:
|
case CMD_ORIGIN:
|
||||||
{
|
{
|
||||||
LOG(SERIALINTERFACE, "SI - Get Origin");
|
LOG(SERIALINTERFACE, "SI - Get Origin");
|
||||||
u8* pCalibration = reinterpret_cast<u8*>(&m_origin);
|
u8* pCalibration = reinterpret_cast<u8*>(&m_origin);
|
||||||
for (int i = 0; i < (int)sizeof(SOrigin); i++)
|
for (int i = 0; i < (int)sizeof(SOrigin); i++)
|
||||||
{
|
{
|
||||||
_pBuffer[i ^ 3] = *pCalibration++;
|
_pBuffer[i ^ 3] = *pCalibration++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iPosition = _iLength;
|
iPosition = _iLength;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Recalibrate (FiRES: i am not 100 percent sure about this)
|
// Recalibrate (FiRES: i am not 100 percent sure about this)
|
||||||
case CMD_RECALIBRATE:
|
case CMD_RECALIBRATE:
|
||||||
{
|
{
|
||||||
LOG(SERIALINTERFACE, "SI - Recalibrate");
|
LOG(SERIALINTERFACE, "SI - Recalibrate");
|
||||||
u8* pCalibration = reinterpret_cast<u8*>(&m_origin);
|
u8* pCalibration = reinterpret_cast<u8*>(&m_origin);
|
||||||
for (int i = 0; i < (int)sizeof(SOrigin); i++)
|
for (int i = 0; i < (int)sizeof(SOrigin); i++)
|
||||||
{
|
{
|
||||||
_pBuffer[i ^ 3] = *pCalibration++;
|
_pBuffer[i ^ 3] = *pCalibration++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iPosition = _iLength;
|
iPosition = _iLength;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// WII Something
|
// WII Something
|
||||||
case 0xCE:
|
case 0xCE:
|
||||||
LOG(SERIALINTERFACE, "Unknown Wii SI Command");
|
LOG(SERIALINTERFACE, "Unknown Wii SI Command");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DEFAULT
|
// DEFAULT
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command);
|
LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command);
|
||||||
PanicAlert("SI: Unknown command");
|
PanicAlert("SI: Unknown command");
|
||||||
iPosition = _iLength;
|
iPosition = _iLength;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return iPosition;
|
return iPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
// GetData
|
// GetData
|
||||||
//
|
//
|
||||||
// return true on new data (max 7 Bytes and 6 bits ;)
|
// return true on new data (max 7 Bytes and 6 bits ;)
|
||||||
//
|
//
|
||||||
bool
|
bool
|
||||||
CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
|
CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
|
||||||
{
|
{
|
||||||
SPADStatus PadStatus;
|
SPADStatus PadStatus;
|
||||||
memset(&PadStatus, 0 ,sizeof(PadStatus));
|
memset(&PadStatus, 0 ,sizeof(PadStatus));
|
||||||
PluginPAD::PAD_GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
|
PluginPAD::PAD_GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
|
||||||
|
|
||||||
_Hi = (u32)((u8)PadStatus.stickY);
|
_Hi = (u32)((u8)PadStatus.stickY);
|
||||||
_Hi |= (u32)((u8)PadStatus.stickX << 8);
|
_Hi |= (u32)((u8)PadStatus.stickX << 8);
|
||||||
_Hi |= (u32)((u16)PadStatus.button << 16);
|
_Hi |= (u32)((u16)PadStatus.button << 16);
|
||||||
|
|
||||||
_Low = (u8)PadStatus.triggerRight;
|
_Low = (u8)PadStatus.triggerRight;
|
||||||
_Low |= (u32)((u8)PadStatus.triggerLeft << 8);
|
_Low |= (u32)((u8)PadStatus.triggerLeft << 8);
|
||||||
_Low |= (u32)((u8)PadStatus.substickY << 16);
|
_Low |= (u32)((u8)PadStatus.substickY << 16);
|
||||||
_Low |= (u32)((u8)PadStatus.substickX << 24);
|
_Low |= (u32)((u8)PadStatus.substickX << 24);
|
||||||
SetMic(PadStatus.MicButton);
|
SetMic(PadStatus.MicButton);
|
||||||
|
|
||||||
// F|RES:
|
// F|RES:
|
||||||
// i dunno if i should force it here
|
// i dunno if i should force it here
|
||||||
// means that the pad must be "combined" with the origin to math the "final" OSPad-Struct
|
// means that the pad must be "combined" with the origin to math the "final" OSPad-Struct
|
||||||
_Hi |= 0x00800000;
|
_Hi |= 0x00800000;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
// SendCommand
|
// SendCommand
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
CSIDevice_GCController::SendCommand(u32 _Cmd)
|
CSIDevice_GCController::SendCommand(u32 _Cmd)
|
||||||
{
|
{
|
||||||
UCommand command(_Cmd);
|
UCommand command(_Cmd);
|
||||||
switch(command.Command)
|
switch(command.Command)
|
||||||
{
|
{
|
||||||
// Costis sent it in some demos :)
|
// Costis sent it in some demos :)
|
||||||
case 0x00:
|
case 0x00:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_RUMBLE:
|
case CMD_RUMBLE:
|
||||||
{
|
{
|
||||||
unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard
|
unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard
|
||||||
unsigned int uStrength = command.Parameter2;
|
unsigned int uStrength = command.Parameter2;
|
||||||
if (PluginPAD::PAD_Rumble)
|
if (PluginPAD::PAD_Rumble)
|
||||||
PluginPAD::PAD_Rumble(ISIDevice::m_iDeviceNumber, uType, uStrength);
|
PluginPAD::PAD_Rumble(ISIDevice::m_iDeviceNumber, uType, uStrength);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd);
|
LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd);
|
||||||
PanicAlert("SI: Unknown direct command");
|
PanicAlert("SI: Unknown direct command");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
// --- dummy device ---
|
// --- dummy device ---
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
|
|
||||||
CSIDevice_Dummy::CSIDevice_Dummy(int _iDeviceNumber) :
|
CSIDevice_Dummy::CSIDevice_Dummy(int _iDeviceNumber) :
|
||||||
ISIDevice(_iDeviceNumber)
|
ISIDevice(_iDeviceNumber)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
int CSIDevice_Dummy::RunBuffer(u8* _pBuffer, int _iLength)
|
int CSIDevice_Dummy::RunBuffer(u8* _pBuffer, int _iLength)
|
||||||
{
|
{
|
||||||
reinterpret_cast<u32*>(_pBuffer)[0] = 0x00000000; // no device
|
reinterpret_cast<u32*>(_pBuffer)[0] = 0x00000000; // no device
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSIDevice_Dummy::GetData(u32& _Hi, u32& _Low)
|
bool CSIDevice_Dummy::GetData(u32& _Hi, u32& _Low)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSIDevice_Dummy::SendCommand(u32 _Cmd)
|
void CSIDevice_Dummy::SendCommand(u32 _Cmd)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,61 +1,61 @@
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
|
|
||||||
Nintendo GameCube ADPCM Decoder Core Class
|
Nintendo GameCube ADPCM Decoder Core Class
|
||||||
Author: Shinji Chiba <ch3@mail.goo.ne.jp>
|
Author: Shinji Chiba <ch3@mail.goo.ne.jp>
|
||||||
|
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
#include "StreamADPCM.H"
|
#include "StreamADPCM.H"
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
float NGCADPCM::iir1[STEREO],
|
float NGCADPCM::iir1[STEREO],
|
||||||
NGCADPCM::iir2[STEREO];
|
NGCADPCM::iir2[STEREO];
|
||||||
|
|
||||||
void NGCADPCM::InitFilter()
|
void NGCADPCM::InitFilter()
|
||||||
{
|
{
|
||||||
iir1[0] = iir1[1] =
|
iir1[0] = iir1[1] =
|
||||||
iir2[0] = iir2[1] = 0.0f;
|
iir2[0] = iir2[1] = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
short NGCADPCM::DecodeSample( int bits, int q, int ch )
|
short NGCADPCM::DecodeSample( int bits, int q, int ch )
|
||||||
{
|
{
|
||||||
static const float coef[4] = { 0.86f, 1.8f, 0.82f, 1.53f };
|
static const float coef[4] = { 0.86f, 1.8f, 0.82f, 1.53f };
|
||||||
float iir_filter;
|
float iir_filter;
|
||||||
|
|
||||||
iir_filter = (float) ((short) (bits << 12) >> (q & 0xf));
|
iir_filter = (float) ((short) (bits << 12) >> (q & 0xf));
|
||||||
switch (q >> 4)
|
switch (q >> 4)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
iir_filter += (iir1[ch] * coef[0]);
|
iir_filter += (iir1[ch] * coef[0]);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
iir_filter += (iir1[ch] * coef[1] - iir2[ch] * coef[2]);
|
iir_filter += (iir1[ch] * coef[1] - iir2[ch] * coef[2]);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
iir_filter += (iir1[ch] * coef[3] - iir2[ch] * coef[0]);
|
iir_filter += (iir1[ch] * coef[3] - iir2[ch] * coef[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
iir2[ch] = iir1[ch];
|
iir2[ch] = iir1[ch];
|
||||||
if ( iir_filter <= -32768.5f )
|
if ( iir_filter <= -32768.5f )
|
||||||
{
|
{
|
||||||
iir1[ch] = -32767.5f;
|
iir1[ch] = -32767.5f;
|
||||||
return -32767;
|
return -32767;
|
||||||
}
|
}
|
||||||
else if ( iir_filter >= 32767.5f )
|
else if ( iir_filter >= 32767.5f )
|
||||||
{
|
{
|
||||||
iir1[ch] = 32767.5f;
|
iir1[ch] = 32767.5f;
|
||||||
return 32767;
|
return 32767;
|
||||||
}
|
}
|
||||||
return (short) ((iir1[ch] = iir_filter) * 0.5f);
|
return (short) ((iir1[ch] = iir_filter) * 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NGCADPCM::DecodeBlock( short *pcm, u8* adpcm)
|
void NGCADPCM::DecodeBlock( short *pcm, u8* adpcm)
|
||||||
{
|
{
|
||||||
int ch = 1;
|
int ch = 1;
|
||||||
int i;
|
int i;
|
||||||
for( i = 0; i < SAMPLES_PER_BLOCK; i++ )
|
for( i = 0; i < SAMPLES_PER_BLOCK; i++ )
|
||||||
{
|
{
|
||||||
pcm[i * STEREO] = DecodeSample( adpcm[i + (ONE_BLOCK_SIZE - SAMPLES_PER_BLOCK)] & 0xf, adpcm[0], 0 );
|
pcm[i * STEREO] = DecodeSample( adpcm[i + (ONE_BLOCK_SIZE - SAMPLES_PER_BLOCK)] & 0xf, adpcm[0], 0 );
|
||||||
pcm[i * STEREO + MONO] = DecodeSample( adpcm[i + (ONE_BLOCK_SIZE - SAMPLES_PER_BLOCK)] >> 4, adpcm[ch], ch );
|
pcm[i * STEREO + MONO] = DecodeSample( adpcm[i + (ONE_BLOCK_SIZE - SAMPLES_PER_BLOCK)] >> 4, adpcm[ch], ch );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,234 +1,234 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "../PatchEngine.h"
|
#include "../PatchEngine.h"
|
||||||
#include "SystemTimers.h"
|
#include "SystemTimers.h"
|
||||||
#include "../Plugins/Plugin_DSP.h"
|
#include "../Plugins/Plugin_DSP.h"
|
||||||
#include "../Plugins/Plugin_Video.h"
|
#include "../Plugins/Plugin_Video.h"
|
||||||
#include "../HW/DSP.h"
|
#include "../HW/DSP.h"
|
||||||
#include "../HW/AudioInterface.h"
|
#include "../HW/AudioInterface.h"
|
||||||
#include "../HW/VideoInterface.h"
|
#include "../HW/VideoInterface.h"
|
||||||
#include "../HW/SerialInterface.h"
|
#include "../HW/SerialInterface.h"
|
||||||
#include "../HW/CommandProcessor.h" // for DC watchdog hack
|
#include "../HW/CommandProcessor.h" // for DC watchdog hack
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
#include "../CoreTiming.h"
|
#include "../CoreTiming.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
#include "../IPC_HLE/WII_IPC_HLE.h"
|
#include "../IPC_HLE/WII_IPC_HLE.h"
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
|
|
||||||
namespace SystemTimers
|
namespace SystemTimers
|
||||||
{
|
{
|
||||||
|
|
||||||
u32 CPU_CORE_CLOCK = 486000000u; // 486 mhz (its not 485, stop bugging me!)
|
u32 CPU_CORE_CLOCK = 486000000u; // 486 mhz (its not 485, stop bugging me!)
|
||||||
|
|
||||||
s64 fakeDec;
|
s64 fakeDec;
|
||||||
|
|
||||||
// ratio of TB and Decrementer to clock cycles
|
// ratio of TB and Decrementer to clock cycles
|
||||||
// With TB clk at 1/4 of BUS clk
|
// With TB clk at 1/4 of BUS clk
|
||||||
// and it seems BUS clk is really 1/3 of CPU clk
|
// and it seems BUS clk is really 1/3 of CPU clk
|
||||||
// note: ZWW is ok and faster with TIMER_RATIO=8 though.
|
// note: ZWW is ok and faster with TIMER_RATIO=8 though.
|
||||||
// !!! POSSIBLE STABLE PERF BOOST HACK THERE !!!
|
// !!! POSSIBLE STABLE PERF BOOST HACK THERE !!!
|
||||||
enum {
|
enum {
|
||||||
TIMER_RATIO = 12
|
TIMER_RATIO = 12
|
||||||
};
|
};
|
||||||
|
|
||||||
int et_Dec;
|
int et_Dec;
|
||||||
int et_VI;
|
int et_VI;
|
||||||
int et_SI;
|
int et_SI;
|
||||||
int et_AI;
|
int et_AI;
|
||||||
int et_AudioFifo;
|
int et_AudioFifo;
|
||||||
int et_DSP;
|
int et_DSP;
|
||||||
int et_IPC_HLE;
|
int et_IPC_HLE;
|
||||||
int et_FakeGPWD; // for DC watchdog hack
|
int et_FakeGPWD; // for DC watchdog hack
|
||||||
|
|
||||||
// These are badly educated guesses
|
// These are badly educated guesses
|
||||||
// Feel free to experiment
|
// Feel free to experiment
|
||||||
int
|
int
|
||||||
// update VI often to let it go through its scanlines with decent accuracy
|
// update VI often to let it go through its scanlines with decent accuracy
|
||||||
// Maybe should actually align this with the scanline update? Current method in
|
// Maybe should actually align this with the scanline update? Current method in
|
||||||
// VideoInterface::Update is stupid!
|
// VideoInterface::Update is stupid!
|
||||||
VI_PERIOD = GetTicksPerSecond() / (60*120),
|
VI_PERIOD = GetTicksPerSecond() / (60*120),
|
||||||
|
|
||||||
// TODO: The SI interfact actually has a register that determines the polling frequency.
|
// TODO: The SI interfact actually has a register that determines the polling frequency.
|
||||||
// We should obey that instead of arbitrarly checking at 60fps.
|
// We should obey that instead of arbitrarly checking at 60fps.
|
||||||
SI_PERIOD = GetTicksPerSecond() / 60, //once a frame is good for controllers
|
SI_PERIOD = GetTicksPerSecond() / 60, //once a frame is good for controllers
|
||||||
|
|
||||||
// This one should simply be determined by the increasing counter in AI.
|
// This one should simply be determined by the increasing counter in AI.
|
||||||
AI_PERIOD = GetTicksPerSecond() / 80,
|
AI_PERIOD = GetTicksPerSecond() / 80,
|
||||||
|
|
||||||
// These shouldn't be period controlled either, most likely.
|
// These shouldn't be period controlled either, most likely.
|
||||||
DSP_PERIOD = GetTicksPerSecond() / 250,
|
DSP_PERIOD = GetTicksPerSecond() / 250,
|
||||||
|
|
||||||
// This is completely arbitrary. If we find that we need lower latency, we can just
|
// This is completely arbitrary. If we find that we need lower latency, we can just
|
||||||
// increase this number.
|
// increase this number.
|
||||||
IPC_HLE_PERIOD = GetTicksPerSecond() / 250,
|
IPC_HLE_PERIOD = GetTicksPerSecond() / 250,
|
||||||
|
|
||||||
// For DC watchdog hack
|
// For DC watchdog hack
|
||||||
// Once every 2 frame-period should be enough.
|
// Once every 2 frame-period should be enough.
|
||||||
// Assuming game's frame-finish-watchdog wait more than 2 emulated frame-period before starting its mess.
|
// Assuming game's frame-finish-watchdog wait more than 2 emulated frame-period before starting its mess.
|
||||||
FAKE_GP_WATCHDOG_PERIOD = GetTicksPerSecond() / 30;
|
FAKE_GP_WATCHDOG_PERIOD = GetTicksPerSecond() / 30;
|
||||||
|
|
||||||
u32 GetTicksPerSecond()
|
u32 GetTicksPerSecond()
|
||||||
{
|
{
|
||||||
return CPU_CORE_CLOCK;
|
return CPU_CORE_CLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ConvertMillisecondsToTicks(u32 _Milliseconds)
|
u32 ConvertMillisecondsToTicks(u32 _Milliseconds)
|
||||||
{
|
{
|
||||||
return GetTicksPerSecond() / 1000 * _Milliseconds;
|
return GetTicksPerSecond() / 1000 * _Milliseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AICallback(u64 userdata, int cyclesLate)
|
void AICallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
// Update disk streaming. All that code really needs a revamp, including replacing the codec with the one
|
// Update disk streaming. All that code really needs a revamp, including replacing the codec with the one
|
||||||
// from in_cube.
|
// from in_cube.
|
||||||
AudioInterface::Update();
|
AudioInterface::Update();
|
||||||
CoreTiming::ScheduleEvent(AI_PERIOD-cyclesLate, et_AI);
|
CoreTiming::ScheduleEvent(AI_PERIOD-cyclesLate, et_AI);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCallback(u64 userdata, int cyclesLate)
|
void DSPCallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
// ~1/6th as many cycles as the period PPC-side.
|
// ~1/6th as many cycles as the period PPC-side.
|
||||||
PluginDSP::DSP_Update(DSP_PERIOD / 6);
|
PluginDSP::DSP_Update(DSP_PERIOD / 6);
|
||||||
CoreTiming::ScheduleEvent(DSP_PERIOD-cyclesLate, et_DSP);
|
CoreTiming::ScheduleEvent(DSP_PERIOD-cyclesLate, et_DSP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioFifoCallback(u64 userdata, int cyclesLate)
|
void AudioFifoCallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
int period = CPU_CORE_CLOCK / (AudioInterface::GetDSPSampleRate() * 4 / 32);
|
int period = CPU_CORE_CLOCK / (AudioInterface::GetDSPSampleRate() * 4 / 32);
|
||||||
DSP::UpdateAudioDMA(); // Push audio to speakers.
|
DSP::UpdateAudioDMA(); // Push audio to speakers.
|
||||||
|
|
||||||
CoreTiming::ScheduleEvent(period - cyclesLate, et_AudioFifo);
|
CoreTiming::ScheduleEvent(period - cyclesLate, et_AudioFifo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IPC_HLE_UpdateCallback(u64 userdata, int cyclesLate)
|
void IPC_HLE_UpdateCallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
WII_IPC_HLE_Interface::Update();
|
WII_IPC_HLE_Interface::Update();
|
||||||
CoreTiming::ScheduleEvent(IPC_HLE_PERIOD-cyclesLate, et_IPC_HLE);
|
CoreTiming::ScheduleEvent(IPC_HLE_PERIOD-cyclesLate, et_IPC_HLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VICallback(u64 userdata, int cyclesLate)
|
void VICallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
VideoInterface::Update();
|
VideoInterface::Update();
|
||||||
CoreTiming::ScheduleEvent(VI_PERIOD-cyclesLate, et_VI);
|
CoreTiming::ScheduleEvent(VI_PERIOD-cyclesLate, et_VI);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SICallback(u64 userdata, int cyclesLate)
|
void SICallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
// This is once per frame - good candidate for patching stuff
|
// This is once per frame - good candidate for patching stuff
|
||||||
PatchEngine::ApplyFramePatches();
|
PatchEngine::ApplyFramePatches();
|
||||||
// Apply AR cheats
|
// Apply AR cheats
|
||||||
PatchEngine::ApplyARPatches();
|
PatchEngine::ApplyARPatches();
|
||||||
// OK, do what we are here to do.
|
// OK, do what we are here to do.
|
||||||
SerialInterface::UpdateDevices();
|
SerialInterface::UpdateDevices();
|
||||||
CoreTiming::ScheduleEvent(SI_PERIOD-cyclesLate, et_SI);
|
CoreTiming::ScheduleEvent(SI_PERIOD-cyclesLate, et_SI);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecrementerCallback(u64 userdata, int cyclesLate)
|
void DecrementerCallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
//Why is fakeDec too big here?
|
//Why is fakeDec too big here?
|
||||||
fakeDec = -1;
|
fakeDec = -1;
|
||||||
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
|
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
|
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecrementerSet()
|
void DecrementerSet()
|
||||||
{
|
{
|
||||||
u32 decValue = PowerPC::ppcState.spr[SPR_DEC];
|
u32 decValue = PowerPC::ppcState.spr[SPR_DEC];
|
||||||
fakeDec = decValue*TIMER_RATIO;
|
fakeDec = decValue*TIMER_RATIO;
|
||||||
CoreTiming::RemoveEvent(et_Dec);
|
CoreTiming::RemoveEvent(et_Dec);
|
||||||
CoreTiming::ScheduleEvent(decValue * TIMER_RATIO, et_Dec);
|
CoreTiming::ScheduleEvent(decValue * TIMER_RATIO, et_Dec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvanceCallback(int cyclesExecuted)
|
void AdvanceCallback(int cyclesExecuted)
|
||||||
{
|
{
|
||||||
fakeDec -= cyclesExecuted;
|
fakeDec -= cyclesExecuted;
|
||||||
u64 timebase_ticks = CoreTiming::GetTicks() / TIMER_RATIO; //works since we are little endian and TL comes first :)
|
u64 timebase_ticks = CoreTiming::GetTicks() / TIMER_RATIO; //works since we are little endian and TL comes first :)
|
||||||
*(u64*)&TL = timebase_ticks;
|
*(u64*)&TL = timebase_ticks;
|
||||||
if (fakeDec >= 0)
|
if (fakeDec >= 0)
|
||||||
PowerPC::ppcState.spr[SPR_DEC] = (u32)fakeDec / TIMER_RATIO;
|
PowerPC::ppcState.spr[SPR_DEC] = (u32)fakeDec / TIMER_RATIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// For DC watchdog hack
|
// For DC watchdog hack
|
||||||
void FakeGPWatchdogCallback(u64 userdata, int cyclesLate)
|
void FakeGPWatchdogCallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
CommandProcessor::WaitForFrameFinish(); // lock CPUThread until frame finish
|
CommandProcessor::WaitForFrameFinish(); // lock CPUThread until frame finish
|
||||||
CoreTiming::ScheduleEvent(FAKE_GP_WATCHDOG_PERIOD-cyclesLate, et_FakeGPWD);
|
CoreTiming::ScheduleEvent(FAKE_GP_WATCHDOG_PERIOD-cyclesLate, et_FakeGPWD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
if (Core::GetStartupParameter().bWii)
|
if (Core::GetStartupParameter().bWii)
|
||||||
{
|
{
|
||||||
CPU_CORE_CLOCK = 721000000;
|
CPU_CORE_CLOCK = 721000000;
|
||||||
VI_PERIOD = GetTicksPerSecond() / (60*120);
|
VI_PERIOD = GetTicksPerSecond() / (60*120);
|
||||||
SI_PERIOD = GetTicksPerSecond() / 60; // once a frame is good for controllers
|
SI_PERIOD = GetTicksPerSecond() / 60; // once a frame is good for controllers
|
||||||
|
|
||||||
// These are the big question marks IMHO :)
|
// These are the big question marks IMHO :)
|
||||||
AI_PERIOD = GetTicksPerSecond() / 80;
|
AI_PERIOD = GetTicksPerSecond() / 80;
|
||||||
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
|
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
|
||||||
|
|
||||||
IPC_HLE_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
|
IPC_HLE_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CPU_CORE_CLOCK = 486000000;
|
CPU_CORE_CLOCK = 486000000;
|
||||||
VI_PERIOD = GetTicksPerSecond() / (60*120);
|
VI_PERIOD = GetTicksPerSecond() / (60*120);
|
||||||
SI_PERIOD = GetTicksPerSecond() / 60; // once a frame is good for controllers
|
SI_PERIOD = GetTicksPerSecond() / 60; // once a frame is good for controllers
|
||||||
|
|
||||||
// These are the big question marks IMHO :)
|
// These are the big question marks IMHO :)
|
||||||
AI_PERIOD = GetTicksPerSecond() / 80;
|
AI_PERIOD = GetTicksPerSecond() / 80;
|
||||||
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.005f);
|
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.005f);
|
||||||
}
|
}
|
||||||
Common::Timer::IncreaseResolution();
|
Common::Timer::IncreaseResolution();
|
||||||
|
|
||||||
et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback);
|
et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback);
|
||||||
et_AI = CoreTiming::RegisterEvent("AICallback", AICallback);
|
et_AI = CoreTiming::RegisterEvent("AICallback", AICallback);
|
||||||
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
|
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
|
||||||
et_SI = CoreTiming::RegisterEvent("SICallback", SICallback);
|
et_SI = CoreTiming::RegisterEvent("SICallback", SICallback);
|
||||||
et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback);
|
et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback);
|
||||||
et_AudioFifo = CoreTiming::RegisterEvent("AudioFifoCallback", AudioFifoCallback);
|
et_AudioFifo = CoreTiming::RegisterEvent("AudioFifoCallback", AudioFifoCallback);
|
||||||
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
|
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
|
||||||
|
|
||||||
CoreTiming::ScheduleEvent(AI_PERIOD, et_AI);
|
CoreTiming::ScheduleEvent(AI_PERIOD, et_AI);
|
||||||
CoreTiming::ScheduleEvent(VI_PERIOD, et_VI);
|
CoreTiming::ScheduleEvent(VI_PERIOD, et_VI);
|
||||||
CoreTiming::ScheduleEvent(DSP_PERIOD, et_DSP);
|
CoreTiming::ScheduleEvent(DSP_PERIOD, et_DSP);
|
||||||
CoreTiming::ScheduleEvent(SI_PERIOD, et_SI);
|
CoreTiming::ScheduleEvent(SI_PERIOD, et_SI);
|
||||||
CoreTiming::ScheduleEvent(CPU_CORE_CLOCK / (32000 * 4 / 32), et_AudioFifo);
|
CoreTiming::ScheduleEvent(CPU_CORE_CLOCK / (32000 * 4 / 32), et_AudioFifo);
|
||||||
|
|
||||||
// For DC watchdog hack
|
// For DC watchdog hack
|
||||||
if (Core::GetStartupParameter().bUseDualCore)
|
if (Core::GetStartupParameter().bUseDualCore)
|
||||||
{
|
{
|
||||||
et_FakeGPWD = CoreTiming::RegisterEvent("FakeGPWatchdogCallback", FakeGPWatchdogCallback);
|
et_FakeGPWD = CoreTiming::RegisterEvent("FakeGPWatchdogCallback", FakeGPWatchdogCallback);
|
||||||
CoreTiming::ScheduleEvent(FAKE_GP_WATCHDOG_PERIOD, et_FakeGPWD);
|
CoreTiming::ScheduleEvent(FAKE_GP_WATCHDOG_PERIOD, et_FakeGPWD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Core::GetStartupParameter().bWii)
|
if (Core::GetStartupParameter().bWii)
|
||||||
CoreTiming::ScheduleEvent(IPC_HLE_PERIOD, et_IPC_HLE);
|
CoreTiming::ScheduleEvent(IPC_HLE_PERIOD, et_IPC_HLE);
|
||||||
|
|
||||||
CoreTiming::RegisterAdvanceCallback(&AdvanceCallback);
|
CoreTiming::RegisterAdvanceCallback(&AdvanceCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
Common::Timer::RestoreResolution();
|
Common::Timer::RestoreResolution();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,134 +1,134 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
#include "WII_IOB.h"
|
#include "WII_IOB.h"
|
||||||
|
|
||||||
namespace WII_IOBridge
|
namespace WII_IOBridge
|
||||||
{
|
{
|
||||||
|
|
||||||
void HWCALL Read8(u8& _rReturnValue, const u32 _Address)
|
void HWCALL Read8(u8& _rReturnValue, const u32 _Address)
|
||||||
{
|
{
|
||||||
_dbg_assert_(WII_IOB, 0);
|
_dbg_assert_(WII_IOB, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HWCALL Read16(u16& _rReturnValue, const u32 _Address)
|
void HWCALL Read16(u16& _rReturnValue, const u32 _Address)
|
||||||
{
|
{
|
||||||
_dbg_assert_(WII_IOB, 0);
|
_dbg_assert_(WII_IOB, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HWCALL Read32(u32& _rReturnValue, const u32 _Address)
|
void HWCALL Read32(u32& _rReturnValue, const u32 _Address)
|
||||||
{
|
{
|
||||||
switch(_Address & 0xFFFF)
|
switch(_Address & 0xFFFF)
|
||||||
{
|
{
|
||||||
case 0xc0: // __VISendI2CData
|
case 0xc0: // __VISendI2CData
|
||||||
_rReturnValue = 0;
|
_rReturnValue = 0;
|
||||||
LOGV(WII_IOB, 2, "IOP: Read32 from 0xc0 = 0x%08x (__VISendI2CData)", _rReturnValue);
|
LOGV(WII_IOB, 2, "IOP: Read32 from 0xc0 = 0x%08x (__VISendI2CData)", _rReturnValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xc4: // __VISendI2CData
|
case 0xc4: // __VISendI2CData
|
||||||
_rReturnValue = 0;
|
_rReturnValue = 0;
|
||||||
LOGV(WII_IOB, 2, "IOP: Read32 from 0xc4 = 0x%08x (__VISendI2CData)", _rReturnValue);
|
LOGV(WII_IOB, 2, "IOP: Read32 from 0xc4 = 0x%08x (__VISendI2CData)", _rReturnValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xc8: // __VISendI2CData
|
case 0xc8: // __VISendI2CData
|
||||||
_rReturnValue = 0;
|
_rReturnValue = 0;
|
||||||
LOGV(WII_IOB, 2, "IOP: Read32 from 0xc8 = 0x%08x (__VISendI2CData)", _rReturnValue);
|
LOGV(WII_IOB, 2, "IOP: Read32 from 0xc8 = 0x%08x (__VISendI2CData)", _rReturnValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x180: // __AIClockInit
|
case 0x180: // __AIClockInit
|
||||||
_rReturnValue = 0;
|
_rReturnValue = 0;
|
||||||
LOG(WII_IOB, "IOP: Read32 from 0x180 = 0x%08x (__AIClockInit)", _rReturnValue);
|
LOG(WII_IOB, "IOP: Read32 from 0x180 = 0x%08x (__AIClockInit)", _rReturnValue);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x1CC: // __AIClockInit
|
case 0x1CC: // __AIClockInit
|
||||||
_rReturnValue = 0;
|
_rReturnValue = 0;
|
||||||
LOG(WII_IOB, "IOP: Read32 from 0x1CC = 0x%08x (__AIClockInit)", _rReturnValue);
|
LOG(WII_IOB, "IOP: Read32 from 0x1CC = 0x%08x (__AIClockInit)", _rReturnValue);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x1D0: // __AIClockInit
|
case 0x1D0: // __AIClockInit
|
||||||
_rReturnValue = 0;
|
_rReturnValue = 0;
|
||||||
LOG(WII_IOB, "IOP: Read32 from 0x1D0 = 0x%08x (__AIClockInit)", _rReturnValue);
|
LOG(WII_IOB, "IOP: Read32 from 0x1D0 = 0x%08x (__AIClockInit)", _rReturnValue);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_dbg_assert_msg_(WII_IOB, 0, "IOP: Read32 from 0x%08x", _Address);
|
_dbg_assert_msg_(WII_IOB, 0, "IOP: Read32 from 0x%08x", _Address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HWCALL Read64(u64& _rReturnValue, const u32 _Address)
|
void HWCALL Read64(u64& _rReturnValue, const u32 _Address)
|
||||||
{
|
{
|
||||||
_dbg_assert_(WII_IOB, 0);
|
_dbg_assert_(WII_IOB, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HWCALL Write8(const u8 _Value, const u32 _Address)
|
void HWCALL Write8(const u8 _Value, const u32 _Address)
|
||||||
{
|
{
|
||||||
_dbg_assert_(WII_IOB, 0);
|
_dbg_assert_(WII_IOB, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HWCALL Write16(const u16 _Value, const u32 _Address)
|
void HWCALL Write16(const u16 _Value, const u32 _Address)
|
||||||
{
|
{
|
||||||
_dbg_assert_(WII_IOB, 0);
|
_dbg_assert_(WII_IOB, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HWCALL Write32(const u32 _Value, const u32 _Address)
|
void HWCALL Write32(const u32 _Value, const u32 _Address)
|
||||||
{
|
{
|
||||||
switch(_Address & 0xFFFF)
|
switch(_Address & 0xFFFF)
|
||||||
{
|
{
|
||||||
case 0xc0: // __VISendI2CData
|
case 0xc0: // __VISendI2CData
|
||||||
LOGV(WII_IOB, 2, "IOP: Write32 to 0xc0 = 0x%08x (__VISendI2CData)", _Value);
|
LOGV(WII_IOB, 2, "IOP: Write32 to 0xc0 = 0x%08x (__VISendI2CData)", _Value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xc4: // __VISendI2CData
|
case 0xc4: // __VISendI2CData
|
||||||
LOGV(WII_IOB, 2, "IOP: Write32 to 0xc4 = 0x%08x (__VISendI2CData)", _Value);
|
LOGV(WII_IOB, 2, "IOP: Write32 to 0xc4 = 0x%08x (__VISendI2CData)", _Value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xc8: // __VISendI2CData
|
case 0xc8: // __VISendI2CData
|
||||||
LOGV(WII_IOB, 2, "IOP: Write32 to 0xc8 = 0x%08x (__VISendI2CData)", _Value);
|
LOGV(WII_IOB, 2, "IOP: Write32 to 0xc8 = 0x%08x (__VISendI2CData)", _Value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x180: // __AIClockInit
|
case 0x180: // __AIClockInit
|
||||||
LOG(WII_IOB, "IOP: Write32 to 0x180 = 0x%08x (__AIClockInit)", _Value);
|
LOG(WII_IOB, "IOP: Write32 to 0x180 = 0x%08x (__AIClockInit)", _Value);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x1CC: // __AIClockInit
|
case 0x1CC: // __AIClockInit
|
||||||
LOG(WII_IOB, "IOP: Write32 to 0x1D0 = 0x%08x (__AIClockInit)", _Value);
|
LOG(WII_IOB, "IOP: Write32 to 0x1D0 = 0x%08x (__AIClockInit)", _Value);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x1D0: // __AIClockInit
|
case 0x1D0: // __AIClockInit
|
||||||
LOG(WII_IOB, "IOP: Write32 to 0x1D0 = 0x%08x (__AIClockInit)", _Value);
|
LOG(WII_IOB, "IOP: Write32 to 0x1D0 = 0x%08x (__AIClockInit)", _Value);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_dbg_assert_msg_(WII_IOB, 0, "IOP: Write32 to 0x%08x", _Address);
|
_dbg_assert_msg_(WII_IOB, 0, "IOP: Write32 to 0x%08x", _Address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HWCALL Write64(const u64 _Value, const u32 _Address)
|
void HWCALL Write64(const u64 _Value, const u32 _Address)
|
||||||
{
|
{
|
||||||
//switch(_Address)
|
//switch(_Address)
|
||||||
//{
|
//{
|
||||||
//default:
|
//default:
|
||||||
_dbg_assert_msg_(WII_IOB, 0, "IOP: Write32 to 0x%08x", _Address);
|
_dbg_assert_msg_(WII_IOB, 0, "IOP: Write32 to 0x%08x", _Address);
|
||||||
//break;
|
//break;
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace AudioInterfac
|
} // end of namespace AudioInterfac
|
||||||
|
|
|
@ -1,262 +1,262 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
|
|
||||||
#include "CPU.h"
|
#include "CPU.h"
|
||||||
#include "Memmap.h"
|
#include "Memmap.h"
|
||||||
#include "PeripheralInterface.h"
|
#include "PeripheralInterface.h"
|
||||||
|
|
||||||
#include "../IPC_HLE/WII_IPC_HLE.h"
|
#include "../IPC_HLE/WII_IPC_HLE.h"
|
||||||
#include "WII_IPC.h"
|
#include "WII_IPC.h"
|
||||||
|
|
||||||
namespace WII_IPCInterface
|
namespace WII_IPCInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
IPC_COMMAND_REGISTER = 0x00,
|
IPC_COMMAND_REGISTER = 0x00,
|
||||||
IPC_CONTROL_REGISTER = 0x04,
|
IPC_CONTROL_REGISTER = 0x04,
|
||||||
IPC_REPLY_REGISTER = 0x08,
|
IPC_REPLY_REGISTER = 0x08,
|
||||||
IPC_STATUS_REGISTER = 0x30,
|
IPC_STATUS_REGISTER = 0x30,
|
||||||
IPC_CONFIG_REGISTER = 0x34,
|
IPC_CONFIG_REGISTER = 0x34,
|
||||||
IPC_SENSOR_BAR_POWER_REGISTER = 0xC0
|
IPC_SENSOR_BAR_POWER_REGISTER = 0xC0
|
||||||
};
|
};
|
||||||
|
|
||||||
union UIPC_Control
|
union UIPC_Control
|
||||||
{
|
{
|
||||||
u32 Hex;
|
u32 Hex;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned ExecuteCmd : 1;
|
unsigned ExecuteCmd : 1;
|
||||||
unsigned AckReady : 1;
|
unsigned AckReady : 1;
|
||||||
unsigned ReplyReady : 1;
|
unsigned ReplyReady : 1;
|
||||||
unsigned Relaunch : 1;
|
unsigned Relaunch : 1;
|
||||||
unsigned unk5 : 1;
|
unsigned unk5 : 1;
|
||||||
unsigned unk6 : 1;
|
unsigned unk6 : 1;
|
||||||
unsigned pad : 26;
|
unsigned pad : 26;
|
||||||
};
|
};
|
||||||
UIPC_Control(u32 _Hex = 0) {Hex = _Hex;}
|
UIPC_Control(u32 _Hex = 0) {Hex = _Hex;}
|
||||||
};
|
};
|
||||||
|
|
||||||
union UIPC_Status
|
union UIPC_Status
|
||||||
{
|
{
|
||||||
u32 Hex;
|
u32 Hex;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned : 30;
|
unsigned : 30;
|
||||||
unsigned INTERRUPT : 1; // 0x40000000
|
unsigned INTERRUPT : 1; // 0x40000000
|
||||||
unsigned : 1;
|
unsigned : 1;
|
||||||
};
|
};
|
||||||
UIPC_Status(u32 _Hex = 0) {Hex = _Hex;}
|
UIPC_Status(u32 _Hex = 0) {Hex = _Hex;}
|
||||||
};
|
};
|
||||||
|
|
||||||
union UIPC_Config
|
union UIPC_Config
|
||||||
{
|
{
|
||||||
u32 Hex;
|
u32 Hex;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned : 30;
|
unsigned : 30;
|
||||||
unsigned INT_MASK : 1; // 0x40000000
|
unsigned INT_MASK : 1; // 0x40000000
|
||||||
unsigned : 1;
|
unsigned : 1;
|
||||||
};
|
};
|
||||||
UIPC_Config(u32 _Hex = 0)
|
UIPC_Config(u32 _Hex = 0)
|
||||||
{
|
{
|
||||||
Hex = _Hex;
|
Hex = _Hex;
|
||||||
INT_MASK = 1;
|
INT_MASK = 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
UIPC_Status g_IPC_Status;
|
UIPC_Status g_IPC_Status;
|
||||||
UIPC_Config g_IPC_Config;
|
UIPC_Config g_IPC_Config;
|
||||||
UIPC_Control g_IPC_Control;
|
UIPC_Control g_IPC_Control;
|
||||||
|
|
||||||
u32 g_Address = 0;
|
u32 g_Address = 0;
|
||||||
u32 g_Reply = 0;
|
u32 g_Reply = 0;
|
||||||
u32 g_SensorBarPower = 0;
|
u32 g_SensorBarPower = 0;
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
p.Do(g_IPC_Status);
|
p.Do(g_IPC_Status);
|
||||||
p.Do(g_IPC_Config);
|
p.Do(g_IPC_Config);
|
||||||
p.Do(g_IPC_Control);
|
p.Do(g_IPC_Control);
|
||||||
p.Do(g_Address);
|
p.Do(g_Address);
|
||||||
p.Do(g_Reply);
|
p.Do(g_Reply);
|
||||||
p.Do(g_SensorBarPower);
|
p.Do(g_SensorBarPower);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateInterrupts();
|
void UpdateInterrupts();
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
g_Address = 0;
|
g_Address = 0;
|
||||||
g_Reply = 0;
|
g_Reply = 0;
|
||||||
g_SensorBarPower = 0;
|
g_SensorBarPower = 0;
|
||||||
|
|
||||||
g_IPC_Status = UIPC_Status();
|
g_IPC_Status = UIPC_Status();
|
||||||
g_IPC_Config = UIPC_Config();
|
g_IPC_Config = UIPC_Config();
|
||||||
g_IPC_Control = UIPC_Control();
|
g_IPC_Control = UIPC_Control();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void HWCALL Read32(u32& _rReturnValue, const u32 _Address)
|
void HWCALL Read32(u32& _rReturnValue, const u32 _Address)
|
||||||
{
|
{
|
||||||
switch(_Address & 0xFFFF)
|
switch(_Address & 0xFFFF)
|
||||||
{
|
{
|
||||||
case IPC_CONTROL_REGISTER:
|
case IPC_CONTROL_REGISTER:
|
||||||
|
|
||||||
_rReturnValue = g_IPC_Control.Hex;
|
_rReturnValue = g_IPC_Control.Hex;
|
||||||
|
|
||||||
LOGV(WII_IPC, 2, "IOP: Read32 from IPC_CONTROL_REGISTER(0x04) = 0x%08x", _rReturnValue);
|
LOGV(WII_IPC, 2, "IOP: Read32 from IPC_CONTROL_REGISTER(0x04) = 0x%08x", _rReturnValue);
|
||||||
// CCPU::Break();
|
// CCPU::Break();
|
||||||
|
|
||||||
// if ((REASON_REG & 0x14) == 0x14) CALL IPCReplayHanlder
|
// if ((REASON_REG & 0x14) == 0x14) CALL IPCReplayHanlder
|
||||||
// if ((REASON_REG & 0x22) != 0x22) Jumps to the end
|
// if ((REASON_REG & 0x22) != 0x22) Jumps to the end
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPC_REPLY_REGISTER: // looks a little bit like a callback function
|
case IPC_REPLY_REGISTER: // looks a little bit like a callback function
|
||||||
_rReturnValue = g_Reply;
|
_rReturnValue = g_Reply;
|
||||||
LOGV(WII_IPC, 2, "IOP: Write32 to IPC_REPLAY_REGISTER(0x08) = 0x%08x ", _rReturnValue);
|
LOGV(WII_IPC, 2, "IOP: Write32 to IPC_REPLAY_REGISTER(0x08) = 0x%08x ", _rReturnValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPC_SENSOR_BAR_POWER_REGISTER:
|
case IPC_SENSOR_BAR_POWER_REGISTER:
|
||||||
_rReturnValue = g_SensorBarPower;
|
_rReturnValue = g_SensorBarPower;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_dbg_assert_msg_(WII_IPC, 0, "IOP: Read32 from 0x%08x", _Address);
|
_dbg_assert_msg_(WII_IPC, 0, "IOP: Read32 from 0x%08x", _Address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HWCALL Write32(const u32 _Value, const u32 _Address)
|
void HWCALL Write32(const u32 _Value, const u32 _Address)
|
||||||
{
|
{
|
||||||
switch(_Address & 0xFFFF)
|
switch(_Address & 0xFFFF)
|
||||||
{
|
{
|
||||||
// write only ??
|
// write only ??
|
||||||
case IPC_COMMAND_REGISTER: // __ios_Ipc2 ... a value from __responses is loaded
|
case IPC_COMMAND_REGISTER: // __ios_Ipc2 ... a value from __responses is loaded
|
||||||
{
|
{
|
||||||
g_Address = _Value;
|
g_Address = _Value;
|
||||||
LOGV(WII_IPC, 1, "IOP: Write32 to IPC_ADDRESS_REGISTER(0x00) = 0x%08x", g_Address);
|
LOGV(WII_IPC, 1, "IOP: Write32 to IPC_ADDRESS_REGISTER(0x00) = 0x%08x", g_Address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPC_CONTROL_REGISTER:
|
case IPC_CONTROL_REGISTER:
|
||||||
{
|
{
|
||||||
LOGV(WII_IPC, 1, "IOP: Write32 to IPC_CONTROL_REGISTER(0x04) = 0x%08x (old: 0x%08x)", _Value, g_IPC_Control.Hex);
|
LOGV(WII_IPC, 1, "IOP: Write32 to IPC_CONTROL_REGISTER(0x04) = 0x%08x (old: 0x%08x)", _Value, g_IPC_Control.Hex);
|
||||||
|
|
||||||
UIPC_Control TempControl(_Value);
|
UIPC_Control TempControl(_Value);
|
||||||
_dbg_assert_msg_(WII_IPC, TempControl.pad == 0, "IOP: Write to UIPC_Control.pad", _Address);
|
_dbg_assert_msg_(WII_IPC, TempControl.pad == 0, "IOP: Write to UIPC_Control.pad", _Address);
|
||||||
|
|
||||||
|
|
||||||
if (TempControl.AckReady) { g_IPC_Control.AckReady = 0; }
|
if (TempControl.AckReady) { g_IPC_Control.AckReady = 0; }
|
||||||
if (TempControl.ReplyReady) { g_IPC_Control.ReplyReady = 0; }
|
if (TempControl.ReplyReady) { g_IPC_Control.ReplyReady = 0; }
|
||||||
if (TempControl.Relaunch) { g_IPC_Control.Relaunch = 0; }
|
if (TempControl.Relaunch) { g_IPC_Control.Relaunch = 0; }
|
||||||
|
|
||||||
g_IPC_Control.unk5 = TempControl.unk5;
|
g_IPC_Control.unk5 = TempControl.unk5;
|
||||||
g_IPC_Control.unk6 = TempControl.unk6;
|
g_IPC_Control.unk6 = TempControl.unk6;
|
||||||
g_IPC_Control.pad = TempControl.pad;
|
g_IPC_Control.pad = TempControl.pad;
|
||||||
|
|
||||||
if (TempControl.ExecuteCmd)
|
if (TempControl.ExecuteCmd)
|
||||||
{
|
{
|
||||||
WII_IPC_HLE_Interface::AckCommand(g_Address);
|
WII_IPC_HLE_Interface::AckCommand(g_Address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPC_STATUS_REGISTER: // ACR REGISTER IT IS CALLED IN DEBUG
|
case IPC_STATUS_REGISTER: // ACR REGISTER IT IS CALLED IN DEBUG
|
||||||
{
|
{
|
||||||
UIPC_Status NewStatus(_Value);
|
UIPC_Status NewStatus(_Value);
|
||||||
if (NewStatus.INTERRUPT) g_IPC_Status.INTERRUPT = 0; // clear interrupt
|
if (NewStatus.INTERRUPT) g_IPC_Status.INTERRUPT = 0; // clear interrupt
|
||||||
|
|
||||||
LOGV(WII_IPC, 1, "IOP: Write32 to IPC_STATUS_REGISTER(0x30) = 0x%08x", _Value);
|
LOGV(WII_IPC, 1, "IOP: Write32 to IPC_STATUS_REGISTER(0x30) = 0x%08x", _Value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPC_CONFIG_REGISTER: // __OSInterruptInit (0x40000000)
|
case IPC_CONFIG_REGISTER: // __OSInterruptInit (0x40000000)
|
||||||
{
|
{
|
||||||
LOG(WII_IPC, "IOP: Write32 to IPC_CONFIG_REGISTER(0x33) = 0x%08x", _Value);
|
LOG(WII_IPC, "IOP: Write32 to IPC_CONFIG_REGISTER(0x33) = 0x%08x", _Value);
|
||||||
g_IPC_Config.Hex = _Value;
|
g_IPC_Config.Hex = _Value;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPC_SENSOR_BAR_POWER_REGISTER:
|
case IPC_SENSOR_BAR_POWER_REGISTER:
|
||||||
g_SensorBarPower = _Value;
|
g_SensorBarPower = _Value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
_dbg_assert_msg_(WII_IPC, 0, "IOP: Write32 to 0x%08x", _Address);
|
_dbg_assert_msg_(WII_IPC, 0, "IOP: Write32 to 0x%08x", _Address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the interrupts
|
// update the interrupts
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateInterrupts()
|
void UpdateInterrupts()
|
||||||
{
|
{
|
||||||
if ((g_IPC_Control.AckReady == 1) ||
|
if ((g_IPC_Control.AckReady == 1) ||
|
||||||
(g_IPC_Control.ReplyReady == 1))
|
(g_IPC_Control.ReplyReady == 1))
|
||||||
{
|
{
|
||||||
g_IPC_Status.INTERRUPT = 1;
|
g_IPC_Status.INTERRUPT = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we have to generate an interrupt
|
// check if we have to generate an interrupt
|
||||||
if (g_IPC_Config.INT_MASK & g_IPC_Status.INTERRUPT)
|
if (g_IPC_Config.INT_MASK & g_IPC_Status.INTERRUPT)
|
||||||
{
|
{
|
||||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_WII_IPC, true);
|
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_WII_IPC, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_WII_IPC, false);
|
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_WII_IPC, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsReady()
|
bool IsReady()
|
||||||
{
|
{
|
||||||
return ((g_IPC_Control.ReplyReady == 0) && (g_IPC_Control.AckReady == 0) && (g_IPC_Status.INTERRUPT == 0));
|
return ((g_IPC_Control.ReplyReady == 0) && (g_IPC_Control.AckReady == 0) && (g_IPC_Status.INTERRUPT == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateAck(u32 _AnswerAddress)
|
void GenerateAck(u32 _AnswerAddress)
|
||||||
{
|
{
|
||||||
g_Reply = _AnswerAddress;
|
g_Reply = _AnswerAddress;
|
||||||
g_IPC_Control.AckReady = 1;
|
g_IPC_Control.AckReady = 1;
|
||||||
|
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateReply(u32 _AnswerAddress)
|
void GenerateReply(u32 _AnswerAddress)
|
||||||
{
|
{
|
||||||
g_Reply = _AnswerAddress;
|
g_Reply = _AnswerAddress;
|
||||||
g_IPC_Control.ReplyReady = 1;
|
g_IPC_Control.ReplyReady = 1;
|
||||||
|
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace IPC
|
} // end of namespace IPC
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "Host.h"
|
#include "Host.h"
|
||||||
|
|
||||||
|
|
|
@ -1,480 +1,480 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// File description
|
// File description
|
||||||
// -------------
|
// -------------
|
||||||
/* This is the main Wii IPC file that handles all incoming IPC calls and directs them
|
/* This is the main Wii IPC file that handles all incoming IPC calls and directs them
|
||||||
to the right function.
|
to the right function.
|
||||||
|
|
||||||
IPC basics:
|
IPC basics:
|
||||||
|
|
||||||
Return values for file handles: All IPC calls will generate a return value to 0x04,
|
Return values for file handles: All IPC calls will generate a return value to 0x04,
|
||||||
in case of success they are
|
in case of success they are
|
||||||
Open: DeviceID
|
Open: DeviceID
|
||||||
Close: 0
|
Close: 0
|
||||||
Read: Bytes read
|
Read: Bytes read
|
||||||
Write: Bytes written
|
Write: Bytes written
|
||||||
Seek: Seek position
|
Seek: Seek position
|
||||||
Ioctl: 0 (in addition to that there may be messages to the out buffers)
|
Ioctl: 0 (in addition to that there may be messages to the out buffers)
|
||||||
Ioctlv: 0 (in addition to that there may be messages to the out buffers)
|
Ioctlv: 0 (in addition to that there may be messages to the out buffers)
|
||||||
They will also generate a true or false return for UpdateInterrupts() in WII_IPC.cpp. */
|
They will also generate a true or false return for UpdateInterrupts() in WII_IPC.cpp. */
|
||||||
// =============
|
// =============
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "WII_IPC_HLE.h"
|
#include "WII_IPC_HLE.h"
|
||||||
#include "WII_IPC_HLE_Device.h"
|
#include "WII_IPC_HLE_Device.h"
|
||||||
#include "WII_IPC_HLE_Device_Error.h"
|
#include "WII_IPC_HLE_Device_Error.h"
|
||||||
#include "WII_IPC_HLE_Device_DI.h"
|
#include "WII_IPC_HLE_Device_DI.h"
|
||||||
#include "WII_IPC_HLE_Device_FileIO.h"
|
#include "WII_IPC_HLE_Device_FileIO.h"
|
||||||
#include "WII_IPC_HLE_Device_stm.h"
|
#include "WII_IPC_HLE_Device_stm.h"
|
||||||
#include "WII_IPC_HLE_Device_fs.h"
|
#include "WII_IPC_HLE_Device_fs.h"
|
||||||
#include "WII_IPC_HLE_Device_net.h"
|
#include "WII_IPC_HLE_Device_net.h"
|
||||||
#include "WII_IPC_HLE_Device_es.h"
|
#include "WII_IPC_HLE_Device_es.h"
|
||||||
#include "WII_IPC_HLE_Device_usb.h"
|
#include "WII_IPC_HLE_Device_usb.h"
|
||||||
#include "WII_IPC_HLE_Device_sdio_slot0.h"
|
#include "WII_IPC_HLE_Device_sdio_slot0.h"
|
||||||
|
|
||||||
#include "FileUtil.h" // For Copy
|
#include "FileUtil.h" // For Copy
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
#include "../HW/CPU.h"
|
#include "../HW/CPU.h"
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
#include "../HW/WII_IPC.h"
|
#include "../HW/WII_IPC.h"
|
||||||
#include "../Debugger/Debugger_SymbolMap.h"
|
#include "../Debugger/Debugger_SymbolMap.h"
|
||||||
|
|
||||||
namespace WII_IPC_HLE_Interface
|
namespace WII_IPC_HLE_Interface
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
typedef std::map<u32, IWII_IPC_HLE_Device*> TDeviceMap;
|
typedef std::map<u32, IWII_IPC_HLE_Device*> TDeviceMap;
|
||||||
TDeviceMap g_DeviceMap;
|
TDeviceMap g_DeviceMap;
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
u32 g_LastDeviceID = 0x13370000;
|
u32 g_LastDeviceID = 0x13370000;
|
||||||
std::list<u32> g_Ack;
|
std::list<u32> g_Ack;
|
||||||
std::queue<std::pair<u32,std::string> > g_ReplyQueue;
|
std::queue<std::pair<u32,std::string> > g_ReplyQueue;
|
||||||
void ExecuteCommand(u32 _Address);
|
void ExecuteCommand(u32 _Address);
|
||||||
|
|
||||||
// General IPC functions
|
// General IPC functions
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
_dbg_assert_msg_(WII_IPC, g_DeviceMap.empty(), "DeviceMap isnt empty on init");
|
_dbg_assert_msg_(WII_IPC, g_DeviceMap.empty(), "DeviceMap isnt empty on init");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
|
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
|
||||||
while(itr != g_DeviceMap.end())
|
while(itr != g_DeviceMap.end())
|
||||||
{
|
{
|
||||||
delete itr->second;
|
delete itr->second;
|
||||||
++itr;
|
++itr;
|
||||||
}
|
}
|
||||||
g_DeviceMap.clear();
|
g_DeviceMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetDeviceIDByName(const std::string& _rDeviceName)
|
u32 GetDeviceIDByName(const std::string& _rDeviceName)
|
||||||
{
|
{
|
||||||
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
|
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
|
||||||
while(itr != g_DeviceMap.end())
|
while(itr != g_DeviceMap.end())
|
||||||
{
|
{
|
||||||
if (itr->second->GetDeviceName() == _rDeviceName)
|
if (itr->second->GetDeviceName() == _rDeviceName)
|
||||||
return itr->first;
|
return itr->first;
|
||||||
|
|
||||||
++itr;
|
++itr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
|
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
|
||||||
{
|
{
|
||||||
if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
|
if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
|
||||||
return g_DeviceMap[_ID];
|
return g_DeviceMap[_ID];
|
||||||
|
|
||||||
_dbg_assert_msg_(WII_IPC, 0, "IOP tries to access an unknown device 0x%x", _ID);
|
_dbg_assert_msg_(WII_IPC, 0, "IOP tries to access an unknown device 0x%x", _ID);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteDeviceByID(u32 ID)
|
void DeleteDeviceByID(u32 ID)
|
||||||
{
|
{
|
||||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(ID);
|
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(ID);
|
||||||
if (pDevice != NULL)
|
if (pDevice != NULL)
|
||||||
{
|
{
|
||||||
delete pDevice;
|
delete pDevice;
|
||||||
g_DeviceMap.erase(ID);
|
g_DeviceMap.erase(ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called from COMMAND_OPEN_DEVICE. Here we either create a new device
|
// This is called from COMMAND_OPEN_DEVICE. Here we either create a new device
|
||||||
// or open a new file handle.
|
// or open a new file handle.
|
||||||
IWII_IPC_HLE_Device* CreateDevice(u32 _DeviceID, const std::string& _rDeviceName)
|
IWII_IPC_HLE_Device* CreateDevice(u32 _DeviceID, const std::string& _rDeviceName)
|
||||||
{
|
{
|
||||||
// scan device name and create the right one
|
// scan device name and create the right one
|
||||||
IWII_IPC_HLE_Device* pDevice = NULL;
|
IWII_IPC_HLE_Device* pDevice = NULL;
|
||||||
if (_rDeviceName.find("/dev/") != std::string::npos)
|
if (_rDeviceName.find("/dev/") != std::string::npos)
|
||||||
{
|
{
|
||||||
if (_rDeviceName.c_str() == std::string("/dev/stm/immediate"))
|
if (_rDeviceName.c_str() == std::string("/dev/stm/immediate"))
|
||||||
{
|
{
|
||||||
pDevice = new CWII_IPC_HLE_Device_stm_immediate(_DeviceID, _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_stm_immediate(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
else if (_rDeviceName.c_str() == std::string("/dev/stm/eventhook"))
|
else if (_rDeviceName.c_str() == std::string("/dev/stm/eventhook"))
|
||||||
{
|
{
|
||||||
pDevice = new CWII_IPC_HLE_Device_stm_eventhook(_DeviceID, _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_stm_eventhook(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
else if (_rDeviceName.c_str() == std::string("/dev/di"))
|
else if (_rDeviceName.c_str() == std::string("/dev/di"))
|
||||||
{
|
{
|
||||||
pDevice = new CWII_IPC_HLE_Device_di(_DeviceID, _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_di(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
else if (_rDeviceName.c_str() == std::string("/dev/fs"))
|
else if (_rDeviceName.c_str() == std::string("/dev/fs"))
|
||||||
{
|
{
|
||||||
pDevice = new CWII_IPC_HLE_Device_fs(_DeviceID, _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_fs(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
else if (_rDeviceName.c_str() == std::string("/dev/net/kd/request"))
|
else if (_rDeviceName.c_str() == std::string("/dev/net/kd/request"))
|
||||||
{
|
{
|
||||||
pDevice = new CWII_IPC_HLE_Device_net_kd_request(_DeviceID, _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_net_kd_request(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
else if (_rDeviceName.c_str() == std::string("/dev/net/kd/time"))
|
else if (_rDeviceName.c_str() == std::string("/dev/net/kd/time"))
|
||||||
{
|
{
|
||||||
pDevice = new CWII_IPC_HLE_Device_net_kd_time(_DeviceID, _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_net_kd_time(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
else if (_rDeviceName.c_str() == std::string("/dev/net/ncd/manage"))
|
else if (_rDeviceName.c_str() == std::string("/dev/net/ncd/manage"))
|
||||||
{
|
{
|
||||||
pDevice = new CWII_IPC_HLE_Device_net_ncd_manage(_DeviceID, _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_net_ncd_manage(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
else if (_rDeviceName.c_str() == std::string("/dev/es"))
|
else if (_rDeviceName.c_str() == std::string("/dev/es"))
|
||||||
{
|
{
|
||||||
pDevice = new CWII_IPC_HLE_Device_es(_DeviceID, _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_es(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
else if (_rDeviceName.find("/dev/usb/oh1/57e/305") != std::string::npos)
|
else if (_rDeviceName.find("/dev/usb/oh1/57e/305") != std::string::npos)
|
||||||
{
|
{
|
||||||
pDevice = new CWII_IPC_HLE_Device_usb_oh1_57e_305(_DeviceID, _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_usb_oh1_57e_305(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
else if (_rDeviceName.find("/dev/sdio/slot0") != std::string::npos)
|
else if (_rDeviceName.find("/dev/sdio/slot0") != std::string::npos)
|
||||||
{
|
{
|
||||||
pDevice = new CWII_IPC_HLE_Device_sdio_slot0(_DeviceID, _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_sdio_slot0(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PanicAlert("Unknown device: %s", _rDeviceName.c_str());
|
PanicAlert("Unknown device: %s", _rDeviceName.c_str());
|
||||||
pDevice = new CWII_IPC_HLE_Device_Error(u32(-1), _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_Error(u32(-1), _rDeviceName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOGV(WII_IPC_FILEIO, 0, "IOP: Create Device %s", _rDeviceName.c_str());
|
LOGV(WII_IPC_FILEIO, 0, "IOP: Create Device %s", _rDeviceName.c_str());
|
||||||
pDevice = new CWII_IPC_HLE_Device_FileIO(_DeviceID, _rDeviceName);
|
pDevice = new CWII_IPC_HLE_Device_FileIO(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pDevice;
|
return pDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===================================================
|
// ===================================================
|
||||||
/* This generates an acknowledgment to IPC calls. This function is called from
|
/* This generates an acknowledgment to IPC calls. This function is called from
|
||||||
IPC_CONTROL_REGISTER requests in WII_IPC.cpp. The acknowledgment _Address will
|
IPC_CONTROL_REGISTER requests in WII_IPC.cpp. The acknowledgment _Address will
|
||||||
start with 0x033e...., it will be for the _CommandAddress 0x133e...., from
|
start with 0x033e...., it will be for the _CommandAddress 0x133e...., from
|
||||||
debugging I also noticed that the Ioctl arguments are stored temporarily in
|
debugging I also noticed that the Ioctl arguments are stored temporarily in
|
||||||
0x933e.... with the same .... as in the _CommandAddress. */
|
0x933e.... with the same .... as in the _CommandAddress. */
|
||||||
// ----------------
|
// ----------------
|
||||||
bool AckCommand(u32 _Address)
|
bool AckCommand(u32 _Address)
|
||||||
{
|
{
|
||||||
Debugger::PrintCallstack(LogTypes::WII_IPC_HLE);
|
Debugger::PrintCallstack(LogTypes::WII_IPC_HLE);
|
||||||
LOGV(WII_IPC_HLE, 1, "AckCommand: 0%08x", _Address);
|
LOGV(WII_IPC_HLE, 1, "AckCommand: 0%08x", _Address);
|
||||||
|
|
||||||
std::list<u32>::iterator itr = g_Ack.begin();
|
std::list<u32>::iterator itr = g_Ack.begin();
|
||||||
while (itr != g_Ack.end())
|
while (itr != g_Ack.end())
|
||||||
{
|
{
|
||||||
if (*itr == _Address)
|
if (*itr == _Address)
|
||||||
{
|
{
|
||||||
PanicAlert("execute a command two times");
|
PanicAlert("execute a command two times");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
itr++;
|
itr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_Ack.push_back(_Address);
|
g_Ack.push_back(_Address);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let the game read the setting.txt file
|
// Let the game read the setting.txt file
|
||||||
void CopySettingsFile(std::string DeviceName)
|
void CopySettingsFile(std::string DeviceName)
|
||||||
{
|
{
|
||||||
std::string Source = FULL_WII_SYS_DIR;
|
std::string Source = FULL_WII_SYS_DIR;
|
||||||
if(Core::GetStartupParameter().bNTSC)
|
if(Core::GetStartupParameter().bNTSC)
|
||||||
Source += "setting-usa.txt";
|
Source += "setting-usa.txt";
|
||||||
else
|
else
|
||||||
Source += "setting-eur.txt";
|
Source += "setting-eur.txt";
|
||||||
|
|
||||||
std::string Target = FULL_WII_ROOT_DIR + DeviceName;
|
std::string Target = FULL_WII_ROOT_DIR + DeviceName;
|
||||||
|
|
||||||
// Check if the target dir exists, otherwise create it
|
// Check if the target dir exists, otherwise create it
|
||||||
std::string TargetDir = Target.substr(0, Target.find_last_of(DIR_SEP));
|
std::string TargetDir = Target.substr(0, Target.find_last_of(DIR_SEP));
|
||||||
if(!File::IsDirectory(TargetDir.c_str())) File::CreateDirectoryStructure(Target.c_str());
|
if(!File::IsDirectory(TargetDir.c_str())) File::CreateDirectoryStructure(Target.c_str());
|
||||||
|
|
||||||
if (File::Copy(Source.c_str(), Target.c_str()))
|
if (File::Copy(Source.c_str(), Target.c_str()))
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "FS: Copied %s to %s", Source.c_str(), Target.c_str());
|
LOG(WII_IPC_FILEIO, "FS: Copied %s to %s", Source.c_str(), Target.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "Could not copy %s to %s", Source.c_str(), Target.c_str());
|
LOG(WII_IPC_FILEIO, "Could not copy %s to %s", Source.c_str(), Target.c_str());
|
||||||
PanicAlert("Could not copy %s to %s", Source.c_str(), Target.c_str());
|
PanicAlert("Could not copy %s to %s", Source.c_str(), Target.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecuteCommand(u32 _Address)
|
void ExecuteCommand(u32 _Address)
|
||||||
{
|
{
|
||||||
bool GenerateReply = false;
|
bool GenerateReply = false;
|
||||||
u32 erased = 0;
|
u32 erased = 0;
|
||||||
|
|
||||||
ECommandType Command = static_cast<ECommandType>(Memory::Read_U32(_Address));
|
ECommandType Command = static_cast<ECommandType>(Memory::Read_U32(_Address));
|
||||||
switch (Command)
|
switch (Command)
|
||||||
{
|
{
|
||||||
case COMMAND_OPEN_DEVICE:
|
case COMMAND_OPEN_DEVICE:
|
||||||
{
|
{
|
||||||
// Create a new HLE device. The Mode and DeviceName is given to us but we
|
// Create a new HLE device. The Mode and DeviceName is given to us but we
|
||||||
// generate a DeviceID to be used for access to this device until it is Closed.
|
// generate a DeviceID to be used for access to this device until it is Closed.
|
||||||
std::string DeviceName;
|
std::string DeviceName;
|
||||||
Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
|
Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
|
||||||
|
|
||||||
// The game may try to read setting.txt here, in that case copy it so it can read it
|
// The game may try to read setting.txt here, in that case copy it so it can read it
|
||||||
if(DeviceName.find("setting.txt") != std::string::npos) CopySettingsFile(DeviceName);
|
if(DeviceName.find("setting.txt") != std::string::npos) CopySettingsFile(DeviceName);
|
||||||
|
|
||||||
u32 Mode = Memory::Read_U32(_Address + 0x10);
|
u32 Mode = Memory::Read_U32(_Address + 0x10);
|
||||||
u32 DeviceID = GetDeviceIDByName(DeviceName);
|
u32 DeviceID = GetDeviceIDByName(DeviceName);
|
||||||
|
|
||||||
// check if a device with this name has been created already
|
// check if a device with this name has been created already
|
||||||
if (DeviceID == 0)
|
if (DeviceID == 0)
|
||||||
{
|
{
|
||||||
// create the new device
|
// create the new device
|
||||||
// alternatively we could pre create all devices and put them in a directory tree structure
|
// alternatively we could pre create all devices and put them in a directory tree structure
|
||||||
// then this would just return a pointer to the wanted device.
|
// then this would just return a pointer to the wanted device.
|
||||||
u32 CurrentDeviceID = g_LastDeviceID;
|
u32 CurrentDeviceID = g_LastDeviceID;
|
||||||
IWII_IPC_HLE_Device* pDevice = CreateDevice(CurrentDeviceID, DeviceName);
|
IWII_IPC_HLE_Device* pDevice = CreateDevice(CurrentDeviceID, DeviceName);
|
||||||
g_DeviceMap[CurrentDeviceID] = pDevice;
|
g_DeviceMap[CurrentDeviceID] = pDevice;
|
||||||
g_LastDeviceID++;
|
g_LastDeviceID++;
|
||||||
|
|
||||||
GenerateReply = pDevice->Open(_Address, Mode);
|
GenerateReply = pDevice->Open(_Address, Mode);
|
||||||
if(pDevice->GetDeviceName().find("/dev/") == std::string::npos
|
if(pDevice->GetDeviceName().find("/dev/") == std::string::npos
|
||||||
|| pDevice->GetDeviceName().c_str() == std::string("/dev/fs"))
|
|| pDevice->GetDeviceName().c_str() == std::string("/dev/fs"))
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "IOP: Open (Device=%s, DeviceID=%08x, Mode=%i, GenerateReply=%i)",
|
LOG(WII_IPC_FILEIO, "IOP: Open (Device=%s, DeviceID=%08x, Mode=%i, GenerateReply=%i)",
|
||||||
pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode, (int)GenerateReply);
|
pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode, (int)GenerateReply);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_HLE, "IOP: Open (Device=%s, DeviceID=%08x, Mode=%i)",
|
LOG(WII_IPC_HLE, "IOP: Open (Device=%s, DeviceID=%08x, Mode=%i)",
|
||||||
pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode);
|
pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The device has already been opened and was not closed, reuse the same DeviceID.
|
// The device has already been opened and was not closed, reuse the same DeviceID.
|
||||||
|
|
||||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
||||||
// If we return -6 here after a Open > Failed > CREATE_FILE > ReOpen call
|
// If we return -6 here after a Open > Failed > CREATE_FILE > ReOpen call
|
||||||
// sequence Mario Galaxy and Mario Kart Wii will not start writing to the file,
|
// sequence Mario Galaxy and Mario Kart Wii will not start writing to the file,
|
||||||
// it will just (seemingly) wait for one or two seconds and then give an error
|
// it will just (seemingly) wait for one or two seconds and then give an error
|
||||||
// message. So I'm trying to return the DeviceID instead to make it write to the file.
|
// message. So I'm trying to return the DeviceID instead to make it write to the file.
|
||||||
// (Which was most likely the reason it created the file in the first place.) */
|
// (Which was most likely the reason it created the file in the first place.) */
|
||||||
|
|
||||||
// F|RES: prolly the re-open is just a mode change
|
// F|RES: prolly the re-open is just a mode change
|
||||||
|
|
||||||
LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
|
LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
|
||||||
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
|
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
|
||||||
|
|
||||||
if(DeviceName.find("/dev/") == std::string::npos)
|
if(DeviceName.find("/dev/") == std::string::npos)
|
||||||
{
|
{
|
||||||
|
|
||||||
u32 newMode = Memory::Read_U32(_Address + 0x10);
|
u32 newMode = Memory::Read_U32(_Address + 0x10);
|
||||||
|
|
||||||
// We may not have a file handle at this point, in Mario Kart I got a
|
// We may not have a file handle at this point, in Mario Kart I got a
|
||||||
// Open > Failed > ... other stuff > ReOpen call sequence, in that case
|
// Open > Failed > ... other stuff > ReOpen call sequence, in that case
|
||||||
// we have no file and no file handle, so we call Open again to basically
|
// we have no file and no file handle, so we call Open again to basically
|
||||||
// get a -106 error so that the game call CreateFile and then ReOpen again.
|
// get a -106 error so that the game call CreateFile and then ReOpen again.
|
||||||
if(pDevice->ReturnFileHandle())
|
if(pDevice->ReturnFileHandle())
|
||||||
Memory::Write_U32(DeviceID, _Address + 4);
|
Memory::Write_U32(DeviceID, _Address + 4);
|
||||||
else
|
else
|
||||||
GenerateReply = pDevice->Open(_Address, newMode);
|
GenerateReply = pDevice->Open(_Address, newMode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We have already opened this device, return -6
|
// We have already opened this device, return -6
|
||||||
Memory::Write_U32(u32(-6), _Address + 4);
|
Memory::Write_U32(u32(-6), _Address + 4);
|
||||||
}
|
}
|
||||||
GenerateReply = true;
|
GenerateReply = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COMMAND_CLOSE_DEVICE:
|
case COMMAND_CLOSE_DEVICE:
|
||||||
{
|
{
|
||||||
u32 DeviceID = Memory::Read_U32(_Address + 8);
|
u32 DeviceID = Memory::Read_U32(_Address + 8);
|
||||||
|
|
||||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
||||||
if (pDevice != NULL)
|
if (pDevice != NULL)
|
||||||
{
|
{
|
||||||
pDevice->Close(_Address);
|
pDevice->Close(_Address);
|
||||||
|
|
||||||
// Delete the device when CLOSE is called, this does not effect
|
// Delete the device when CLOSE is called, this does not effect
|
||||||
// GenerateReply() for any other purpose than the logging because
|
// GenerateReply() for any other purpose than the logging because
|
||||||
// it's a true / false only function //
|
// it's a true / false only function //
|
||||||
erased = DeviceID;
|
erased = DeviceID;
|
||||||
GenerateReply = true;
|
GenerateReply = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COMMAND_READ:
|
case COMMAND_READ:
|
||||||
{
|
{
|
||||||
u32 DeviceID = Memory::Read_U32(_Address+8);
|
u32 DeviceID = Memory::Read_U32(_Address+8);
|
||||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
||||||
if (pDevice != NULL)
|
if (pDevice != NULL)
|
||||||
GenerateReply = pDevice->Read(_Address);
|
GenerateReply = pDevice->Read(_Address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COMMAND_WRITE:
|
case COMMAND_WRITE:
|
||||||
{
|
{
|
||||||
u32 DeviceID = Memory::Read_U32(_Address+8);
|
u32 DeviceID = Memory::Read_U32(_Address+8);
|
||||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
||||||
if (pDevice != NULL)
|
if (pDevice != NULL)
|
||||||
GenerateReply = pDevice->Write(_Address);
|
GenerateReply = pDevice->Write(_Address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COMMAND_SEEK:
|
case COMMAND_SEEK:
|
||||||
{
|
{
|
||||||
u32 DeviceID = Memory::Read_U32(_Address+8);
|
u32 DeviceID = Memory::Read_U32(_Address+8);
|
||||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
||||||
if (pDevice != NULL)
|
if (pDevice != NULL)
|
||||||
GenerateReply = pDevice->Seek(_Address);
|
GenerateReply = pDevice->Seek(_Address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COMMAND_IOCTL:
|
case COMMAND_IOCTL:
|
||||||
{
|
{
|
||||||
u32 DeviceID = Memory::Read_U32(_Address+8);
|
u32 DeviceID = Memory::Read_U32(_Address+8);
|
||||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
||||||
if (pDevice != NULL)
|
if (pDevice != NULL)
|
||||||
GenerateReply = pDevice->IOCtl(_Address);
|
GenerateReply = pDevice->IOCtl(_Address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COMMAND_IOCTLV:
|
case COMMAND_IOCTLV:
|
||||||
{
|
{
|
||||||
u32 DeviceID = Memory::Read_U32(_Address+8);
|
u32 DeviceID = Memory::Read_U32(_Address+8);
|
||||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
||||||
if (pDevice)
|
if (pDevice)
|
||||||
GenerateReply = pDevice->IOCtlV(_Address);
|
GenerateReply = pDevice->IOCtlV(_Address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown Command %i (0x%08x)", Command, _Address);
|
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown Command %i (0x%08x)", Command, _Address);
|
||||||
CCPU::Break();
|
CCPU::Break();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It seems that the original hardware overwrites the command after it has been
|
// It seems that the original hardware overwrites the command after it has been
|
||||||
// executed. We write 8 which is not any valid command.
|
// executed. We write 8 which is not any valid command.
|
||||||
Memory::Write_U32(8, _Address);
|
Memory::Write_U32(8, _Address);
|
||||||
|
|
||||||
// Generate a reply to the IPC command
|
// Generate a reply to the IPC command
|
||||||
if (GenerateReply)
|
if (GenerateReply)
|
||||||
{
|
{
|
||||||
// Get device id
|
// Get device id
|
||||||
u32 DeviceID = Memory::Read_U32(_Address + 8);
|
u32 DeviceID = Memory::Read_U32(_Address + 8);
|
||||||
IWII_IPC_HLE_Device* pDevice = NULL;
|
IWII_IPC_HLE_Device* pDevice = NULL;
|
||||||
|
|
||||||
// Get the device from the device map
|
// Get the device from the device map
|
||||||
if (DeviceID != 0) {
|
if (DeviceID != 0) {
|
||||||
if (g_DeviceMap.find(DeviceID) != g_DeviceMap.end())
|
if (g_DeviceMap.find(DeviceID) != g_DeviceMap.end())
|
||||||
pDevice = g_DeviceMap[DeviceID];
|
pDevice = g_DeviceMap[DeviceID];
|
||||||
|
|
||||||
if (pDevice != NULL) {
|
if (pDevice != NULL) {
|
||||||
// Write reply, this will later be executed in Update()
|
// Write reply, this will later be executed in Update()
|
||||||
g_ReplyQueue.push(std::pair<u32, std::string>(_Address, pDevice->GetDeviceName()));
|
g_ReplyQueue.push(std::pair<u32, std::string>(_Address, pDevice->GetDeviceName()));
|
||||||
} else {
|
} else {
|
||||||
LOG(WII_IPC_HLE, "IOP: Reply to unknown device ID (DeviceID=%i)", DeviceID);
|
LOG(WII_IPC_HLE, "IOP: Reply to unknown device ID (DeviceID=%i)", DeviceID);
|
||||||
g_ReplyQueue.push(std::pair<u32, std::string>(_Address, "unknown"));
|
g_ReplyQueue.push(std::pair<u32, std::string>(_Address, "unknown"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (erased > 0 && erased == DeviceID)
|
if (erased > 0 && erased == DeviceID)
|
||||||
DeleteDeviceByID(DeviceID);
|
DeleteDeviceByID(DeviceID);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// 0 is ok, as it's used for devices that weren't created yet
|
// 0 is ok, as it's used for devices that weren't created yet
|
||||||
g_ReplyQueue.push(std::pair<u32, std::string>(_Address, "unknown"));
|
g_ReplyQueue.push(std::pair<u32, std::string>(_Address, "unknown"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ===================================================
|
// ===================================================
|
||||||
/* This is called continuously from SystemTimers.cpp and WII_IPCInterface::IsReady()
|
/* This is called continuously from SystemTimers.cpp and WII_IPCInterface::IsReady()
|
||||||
is controlled from WII_IPC.cpp. */
|
is controlled from WII_IPC.cpp. */
|
||||||
// ----------------
|
// ----------------
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
if (WII_IPCInterface::IsReady())
|
if (WII_IPCInterface::IsReady())
|
||||||
{
|
{
|
||||||
// check if an executed must be updated
|
// check if an executed must be updated
|
||||||
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
|
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
|
||||||
while(itr != g_DeviceMap.end())
|
while(itr != g_DeviceMap.end())
|
||||||
{
|
{
|
||||||
u32 CommandAddr = itr->second->Update();
|
u32 CommandAddr = itr->second->Update();
|
||||||
if (CommandAddr != 0)
|
if (CommandAddr != 0)
|
||||||
{
|
{
|
||||||
g_ReplyQueue.push(std::pair<u32, std::string>(CommandAddr, itr->second->GetDeviceName()));
|
g_ReplyQueue.push(std::pair<u32, std::string>(CommandAddr, itr->second->GetDeviceName()));
|
||||||
}
|
}
|
||||||
++itr;
|
++itr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have to execute an acknowledge command...
|
// Check if we have to execute an acknowledge command...
|
||||||
if (!g_ReplyQueue.empty())
|
if (!g_ReplyQueue.empty())
|
||||||
{
|
{
|
||||||
WII_IPCInterface::GenerateReply(g_ReplyQueue.front().first);
|
WII_IPCInterface::GenerateReply(g_ReplyQueue.front().first);
|
||||||
g_ReplyQueue.pop();
|
g_ReplyQueue.pop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...no we don't, we can now execute the IPC command
|
// ...no we don't, we can now execute the IPC command
|
||||||
if (g_ReplyQueue.empty() && !g_Ack.empty())
|
if (g_ReplyQueue.empty() && !g_Ack.empty())
|
||||||
{
|
{
|
||||||
u32 _Address = g_Ack.front();
|
u32 _Address = g_Ack.front();
|
||||||
g_Ack.pop_front();
|
g_Ack.pop_front();
|
||||||
ExecuteCommand(_Address);
|
ExecuteCommand(_Address);
|
||||||
LOGV(WII_IPC_HLE, 1, "-- Generate Ack (0x%08x)", _Address);
|
LOGV(WII_IPC_HLE, 1, "-- Generate Ack (0x%08x)", _Address);
|
||||||
|
|
||||||
// Go back to WII_IPC.cpp and generate an acknowledgement
|
// Go back to WII_IPC.cpp and generate an acknowledgement
|
||||||
WII_IPCInterface::GenerateAck(_Address);
|
WII_IPCInterface::GenerateAck(_Address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace IPC
|
} // end of namespace IPC
|
||||||
|
|
|
@ -1,272 +1,272 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
#include "WII_IPC_HLE_Device_DI.h"
|
#include "WII_IPC_HLE_Device_DI.h"
|
||||||
|
|
||||||
#include "../HW/CPU.h"
|
#include "../HW/CPU.h"
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
|
|
||||||
#include "../VolumeHandler.h"
|
#include "../VolumeHandler.h"
|
||||||
|
|
||||||
#include "VolumeCreator.h"
|
#include "VolumeCreator.h"
|
||||||
#include "Filesystem.h"
|
#include "Filesystem.h"
|
||||||
|
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_di::CWII_IPC_HLE_Device_di(u32 _DeviceID, const std::string& _rDeviceName )
|
CWII_IPC_HLE_Device_di::CWII_IPC_HLE_Device_di(u32 _DeviceID, const std::string& _rDeviceName )
|
||||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
||||||
, m_pVolume(NULL)
|
, m_pVolume(NULL)
|
||||||
, m_pFileSystem(NULL)
|
, m_pFileSystem(NULL)
|
||||||
{
|
{
|
||||||
m_pVolume = VolumeHandler::GetVolume();
|
m_pVolume = VolumeHandler::GetVolume();
|
||||||
if (m_pVolume)
|
if (m_pVolume)
|
||||||
m_pFileSystem = DiscIO::CreateFileSystem(m_pVolume);
|
m_pFileSystem = DiscIO::CreateFileSystem(m_pVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_di::~CWII_IPC_HLE_Device_di()
|
CWII_IPC_HLE_Device_di::~CWII_IPC_HLE_Device_di()
|
||||||
{
|
{
|
||||||
delete m_pFileSystem;
|
delete m_pFileSystem;
|
||||||
delete m_pVolume;
|
delete m_pVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_di::Open(u32 _CommandAddress, u32 _Mode)
|
bool CWII_IPC_HLE_Device_di::Open(u32 _CommandAddress, u32 _Mode)
|
||||||
{
|
{
|
||||||
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
|
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_di::IOCtl(u32 _CommandAddress)
|
bool CWII_IPC_HLE_Device_di::IOCtl(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
LOGV(WII_IPC_DVD, 1, "*******************************");
|
LOGV(WII_IPC_DVD, 1, "*******************************");
|
||||||
LOGV(WII_IPC_DVD, 1, "CWII_IPC_DVD_Device_di::IOCtl");
|
LOGV(WII_IPC_DVD, 1, "CWII_IPC_DVD_Device_di::IOCtl");
|
||||||
LOGV(WII_IPC_DVD, 1, "*******************************");
|
LOGV(WII_IPC_DVD, 1, "*******************************");
|
||||||
|
|
||||||
|
|
||||||
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
||||||
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
||||||
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||||
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
||||||
u32 Command = Memory::Read_U32(BufferIn) >> 24;
|
u32 Command = Memory::Read_U32(BufferIn) >> 24;
|
||||||
|
|
||||||
LOG(WII_IPC_DVD, "%s - Command(0x%08x) BufferIn(0x%08x, 0x%x) BufferOut(0x%08x, 0x%x)", GetDeviceName().c_str(), Command, BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
LOG(WII_IPC_DVD, "%s - Command(0x%08x) BufferIn(0x%08x, 0x%x) BufferOut(0x%08x, 0x%x)", GetDeviceName().c_str(), Command, BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
||||||
|
|
||||||
u32 ReturnValue = ExecuteCommand(BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
u32 ReturnValue = ExecuteCommand(BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_di::IOCtlV(u32 _CommandAddress)
|
bool CWII_IPC_HLE_Device_di::IOCtlV(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
PanicAlert("CWII_IPC_HLE_Device_di::IOCtlV() unknown");
|
PanicAlert("CWII_IPC_HLE_Device_di::IOCtlV() unknown");
|
||||||
|
|
||||||
DumpCommands(_CommandAddress);
|
DumpCommands(_CommandAddress);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize)
|
u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize)
|
||||||
{
|
{
|
||||||
u32 Command = Memory::Read_U32(_BufferIn) >> 24;
|
u32 Command = Memory::Read_U32(_BufferIn) >> 24;
|
||||||
|
|
||||||
/* Set out buffer to zeroes as a safety precaution to avoid answering
|
/* Set out buffer to zeroes as a safety precaution to avoid answering
|
||||||
nonsense values */
|
nonsense values */
|
||||||
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
||||||
|
|
||||||
switch (Command)
|
switch (Command)
|
||||||
{
|
{
|
||||||
// DVDLowInquiry
|
// DVDLowInquiry
|
||||||
case 0x12:
|
case 0x12:
|
||||||
{
|
{
|
||||||
u8* buffer = Memory::GetPointer(_BufferOut);
|
u8* buffer = Memory::GetPointer(_BufferOut);
|
||||||
|
|
||||||
/* In theory this gives a game the option to use different read / write behaviors
|
/* In theory this gives a game the option to use different read / write behaviors
|
||||||
depending on which hardware revision that is used, if there have been more than
|
depending on which hardware revision that is used, if there have been more than
|
||||||
one. But it's probably not used at all by any game, in any case it would be strange
|
one. But it's probably not used at all by any game, in any case it would be strange
|
||||||
if it refused a certain value here if it's possible that that would make it
|
if it refused a certain value here if it's possible that that would make it
|
||||||
incompatible with new DVD drives for example. From an actual Wii the code was
|
incompatible with new DVD drives for example. From an actual Wii the code was
|
||||||
0x0000, 0x0002, 0x20060526, I tried it in Balls of Fury that gives a DVD error
|
0x0000, 0x0002, 0x20060526, I tried it in Balls of Fury that gives a DVD error
|
||||||
message after the DVDLowInquiry, but that did't change anything, it must be
|
message after the DVDLowInquiry, but that did't change anything, it must be
|
||||||
something else. */
|
something else. */
|
||||||
buffer[0] = 0x01; // rev
|
buffer[0] = 0x01; // rev
|
||||||
buffer[1] = 0x02;
|
buffer[1] = 0x02;
|
||||||
buffer[2] = 0x03; // dev code
|
buffer[2] = 0x03; // dev code
|
||||||
buffer[3] = 0x04;
|
buffer[3] = 0x04;
|
||||||
buffer[4] = 0x20; // firmware date
|
buffer[4] = 0x20; // firmware date
|
||||||
buffer[5] = 0x08;
|
buffer[5] = 0x08;
|
||||||
buffer[6] = 0x08;
|
buffer[6] = 0x08;
|
||||||
buffer[7] = 0x29;
|
buffer[7] = 0x29;
|
||||||
|
|
||||||
LOG(WII_IPC_DVD, "%s executes DVDLowInquiry (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
LOG(WII_IPC_DVD, "%s executes DVDLowInquiry (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
||||||
|
|
||||||
return 0x1;
|
return 0x1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DVDLowReadDiskID
|
// DVDLowReadDiskID
|
||||||
case 0x70:
|
case 0x70:
|
||||||
{
|
{
|
||||||
// TODO - verify that this is correct
|
// TODO - verify that this is correct
|
||||||
VolumeHandler::ReadToPtr(Memory::GetPointer(_BufferOut), 0, _BufferOutSize);
|
VolumeHandler::ReadToPtr(Memory::GetPointer(_BufferOut), 0, _BufferOutSize);
|
||||||
|
|
||||||
LOG(WII_IPC_DVD, "%s executes DVDLowReadDiskID (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
LOG(WII_IPC_DVD, "%s executes DVDLowReadDiskID (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
||||||
|
|
||||||
return 0x1;
|
return 0x1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DVDLowRead
|
// DVDLowRead
|
||||||
case 0x71:
|
case 0x71:
|
||||||
{
|
{
|
||||||
u32 Size = Memory::Read_U32(_BufferIn + 0x04);
|
u32 Size = Memory::Read_U32(_BufferIn + 0x04);
|
||||||
u64 DVDAddress = (u64)Memory::Read_U32(_BufferIn + 0x08) << 2;
|
u64 DVDAddress = (u64)Memory::Read_U32(_BufferIn + 0x08) << 2;
|
||||||
|
|
||||||
const char* pFilename = m_pFileSystem->GetFileName(DVDAddress);
|
const char* pFilename = m_pFileSystem->GetFileName(DVDAddress);
|
||||||
if (pFilename != NULL)
|
if (pFilename != NULL)
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_DVD, " DVDLowRead: %s (0x%x) - (DVDAddr: 0x%x, Size: 0x%x)", pFilename, m_pFileSystem->GetFileSize(pFilename), DVDAddress, Size);
|
LOG(WII_IPC_DVD, " DVDLowRead: %s (0x%x) - (DVDAddr: 0x%x, Size: 0x%x)", pFilename, m_pFileSystem->GetFileSize(pFilename), DVDAddress, Size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_DVD, " DVDLowRead: file unkw - (DVDAddr: 0x%x, Size: 0x%x)", GetDeviceName().c_str(), DVDAddress, Size);
|
LOG(WII_IPC_DVD, " DVDLowRead: file unkw - (DVDAddr: 0x%x, Size: 0x%x)", GetDeviceName().c_str(), DVDAddress, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Size > _BufferOutSize)
|
if (Size > _BufferOutSize)
|
||||||
{
|
{
|
||||||
PanicAlert("Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp.");
|
PanicAlert("Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp.");
|
||||||
Size = _BufferOutSize;
|
Size = _BufferOutSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VolumeHandler::ReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size) != true)
|
if (VolumeHandler::ReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size) != true)
|
||||||
{
|
{
|
||||||
PanicAlert("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
|
PanicAlert("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0x1;
|
return 0x1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DVDLowWaitForCoverClose
|
// DVDLowWaitForCoverClose
|
||||||
case 0x79:
|
case 0x79:
|
||||||
{
|
{
|
||||||
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
||||||
LOG(WII_IPC_DVD, "%s executes DVDLowWaitForCoverClose (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
LOG(WII_IPC_DVD, "%s executes DVDLowWaitForCoverClose (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DVDLowGetCoverReg - Called by "Legend of Spyro" and MP3
|
// DVDLowGetCoverReg - Called by "Legend of Spyro" and MP3
|
||||||
case 0x7a:
|
case 0x7a:
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_DVD, "%s executes DVDLowGetCoverReg (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
LOG(WII_IPC_DVD, "%s executes DVDLowGetCoverReg (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
||||||
|
|
||||||
// Write zeroes to the out buffer just in case there is some nonsense data there
|
// Write zeroes to the out buffer just in case there is some nonsense data there
|
||||||
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
/* Hack for Legend of Spyro. Switching the 4th byte between 0 and 1 gets
|
/* Hack for Legend of Spyro. Switching the 4th byte between 0 and 1 gets
|
||||||
through this check. The out buffer address remains the same all the
|
through this check. The out buffer address remains the same all the
|
||||||
time so we don't have to bother making a global function.
|
time so we don't have to bother making a global function.
|
||||||
|
|
||||||
TODO: Make this compatible with MP3 */
|
TODO: Make this compatible with MP3 */
|
||||||
// -------------------------
|
// -------------------------
|
||||||
/*
|
/*
|
||||||
static u8 coverByte = 0;
|
static u8 coverByte = 0;
|
||||||
|
|
||||||
u8* buffer = Memory::GetPointer(_BufferOut);
|
u8* buffer = Memory::GetPointer(_BufferOut);
|
||||||
buffer[3] = coverByte;
|
buffer[3] = coverByte;
|
||||||
|
|
||||||
if(coverByte)
|
if(coverByte)
|
||||||
coverByte = 0;
|
coverByte = 0;
|
||||||
else
|
else
|
||||||
coverByte = 0x01;
|
coverByte = 0x01;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DVDLowClearCoverInterrupt
|
// DVDLowClearCoverInterrupt
|
||||||
case 0x86:
|
case 0x86:
|
||||||
{
|
{
|
||||||
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
||||||
LOGV(WII_IPC_DVD, 1, "%s executes DVDLowClearCoverInterrupt (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
LOGV(WII_IPC_DVD, 1, "%s executes DVDLowClearCoverInterrupt (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DVDLowGetCoverStatus
|
// DVDLowGetCoverStatus
|
||||||
case 0x88:
|
case 0x88:
|
||||||
{
|
{
|
||||||
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
||||||
LOG(WII_IPC_DVD, "%s executes DVDLowGetCoverStatus (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
LOG(WII_IPC_DVD, "%s executes DVDLowGetCoverStatus (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DVDLowReset
|
// DVDLowReset
|
||||||
case 0x8a:
|
case 0x8a:
|
||||||
{
|
{
|
||||||
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
||||||
LOG(WII_IPC_DVD, "%s executes DVDLowReset (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
LOG(WII_IPC_DVD, "%s executes DVDLowReset (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DVDLowOpenPartition
|
// DVDLowOpenPartition
|
||||||
case 0x8b:
|
case 0x8b:
|
||||||
PanicAlert("DVDLowOpenPartition", Command);
|
PanicAlert("DVDLowOpenPartition", Command);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
// DVDLowUnencryptedRead
|
// DVDLowUnencryptedRead
|
||||||
case 0x8d:
|
case 0x8d:
|
||||||
PanicAlert("DVDLowUnencryptedRead");
|
PanicAlert("DVDLowUnencryptedRead");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DVDLowSeek
|
// DVDLowSeek
|
||||||
case 0xab:
|
case 0xab:
|
||||||
// PanicAlert("DVDLowSeek");
|
// PanicAlert("DVDLowSeek");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DVDLowStopMotor
|
// DVDLowStopMotor
|
||||||
case 0xe3:
|
case 0xe3:
|
||||||
{
|
{
|
||||||
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
||||||
u32 eject = Memory::Read_U32(_BufferIn + 0x04);
|
u32 eject = Memory::Read_U32(_BufferIn + 0x04);
|
||||||
|
|
||||||
LOG(WII_IPC_DVD, "%s executes DVDLowStopMotor (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
LOG(WII_IPC_DVD, "%s executes DVDLowStopMotor (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
||||||
|
|
||||||
if(eject)
|
if(eject)
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_DVD, "Eject disc", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
LOG(WII_IPC_DVD, "Eject disc", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
|
||||||
// TODO: eject the disc
|
// TODO: eject the disc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG(WII_IPC_DVD, "%s executes unknown cmd 0x%08x (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), Command, _BufferOut, _BufferOutSize);
|
LOG(WII_IPC_DVD, "%s executes unknown cmd 0x%08x (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), Command, _BufferOut, _BufferOutSize);
|
||||||
|
|
||||||
PanicAlert("%s executes unknown cmd 0x%08x", GetDeviceName().c_str(), Command);
|
PanicAlert("%s executes unknown cmd 0x%08x", GetDeviceName().c_str(), Command);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// i dunno but prolly 1 is okay all the time :)
|
// i dunno but prolly 1 is okay all the time :)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,246 +1,246 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "FileUtil.h"
|
#include "FileUtil.h"
|
||||||
|
|
||||||
#include "WII_IPC_HLE_Device_FileIO.h"
|
#include "WII_IPC_HLE_Device_FileIO.h"
|
||||||
|
|
||||||
|
|
||||||
// ===================================================
|
// ===================================================
|
||||||
/* This is used by several of the FileIO and /dev/fs/ functions */
|
/* This is used by several of the FileIO and /dev/fs/ functions */
|
||||||
// ----------------
|
// ----------------
|
||||||
std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size)
|
std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size)
|
||||||
{
|
{
|
||||||
char Buffer[128];
|
char Buffer[128];
|
||||||
memcpy(Buffer, _pFilename, _size);
|
memcpy(Buffer, _pFilename, _size);
|
||||||
|
|
||||||
std::string Filename(FULL_WII_ROOT_DIR);
|
std::string Filename(FULL_WII_ROOT_DIR);
|
||||||
if (Buffer[1] == '0')
|
if (Buffer[1] == '0')
|
||||||
Filename += std::string("/title"); // this looks and feel like an hack...
|
Filename += std::string("/title"); // this looks and feel like an hack...
|
||||||
|
|
||||||
Filename += Buffer;
|
Filename += Buffer;
|
||||||
|
|
||||||
return Filename;
|
return Filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName )
|
CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName )
|
||||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
||||||
, m_pFileHandle(NULL)
|
, m_pFileHandle(NULL)
|
||||||
, m_FileLength(0)
|
, m_FileLength(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_FileIO::~CWII_IPC_HLE_Device_FileIO()
|
CWII_IPC_HLE_Device_FileIO::~CWII_IPC_HLE_Device_FileIO()
|
||||||
{
|
{
|
||||||
if (m_pFileHandle != NULL)
|
if (m_pFileHandle != NULL)
|
||||||
{
|
{
|
||||||
fclose(m_pFileHandle);
|
fclose(m_pFileHandle);
|
||||||
m_pFileHandle = NULL;
|
m_pFileHandle = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress)
|
CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
u32 DeviceID = Memory::Read_U32(_CommandAddress + 8);
|
u32 DeviceID = Memory::Read_U32(_CommandAddress + 8);
|
||||||
LOG(WII_IPC_FILEIO, "FileIO: Close %s (DeviceID=%08x)", GetDeviceName().c_str(), DeviceID);
|
LOG(WII_IPC_FILEIO, "FileIO: Close %s (DeviceID=%08x)", GetDeviceName().c_str(), DeviceID);
|
||||||
|
|
||||||
// Close always return 0 for success
|
// Close always return 0 for success
|
||||||
Memory::Write_U32(0, _CommandAddress + 4);
|
Memory::Write_U32(0, _CommandAddress + 4);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
|
CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
|
||||||
{
|
{
|
||||||
// close the file handle if we get a reopen
|
// close the file handle if we get a reopen
|
||||||
if (m_pFileHandle != NULL)
|
if (m_pFileHandle != NULL)
|
||||||
{
|
{
|
||||||
fclose(m_pFileHandle);
|
fclose(m_pFileHandle);
|
||||||
m_pFileHandle = NULL;
|
m_pFileHandle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char Modes[][128] =
|
const char Modes[][128] =
|
||||||
{
|
{
|
||||||
{ "Unk Mode" },
|
{ "Unk Mode" },
|
||||||
{ "Read only" },
|
{ "Read only" },
|
||||||
{ "Write only" },
|
{ "Write only" },
|
||||||
{ "Read and Write" }
|
{ "Read and Write" }
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s)", GetDeviceName().c_str(), Modes[_Mode]);
|
LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s)", GetDeviceName().c_str(), Modes[_Mode]);
|
||||||
|
|
||||||
m_Filename = std::string(HLE_IPC_BuildFilename(GetDeviceName().c_str(), 64));
|
m_Filename = std::string(HLE_IPC_BuildFilename(GetDeviceName().c_str(), 64));
|
||||||
|
|
||||||
if (File::Exists(m_Filename.c_str()))
|
if (File::Exists(m_Filename.c_str()))
|
||||||
{
|
{
|
||||||
switch(_Mode)
|
switch(_Mode)
|
||||||
{
|
{
|
||||||
// Do "r+b" for all writing to avoid truncating the file
|
// Do "r+b" for all writing to avoid truncating the file
|
||||||
case 0x01: m_pFileHandle = fopen(m_Filename.c_str(), "rb"); break;
|
case 0x01: m_pFileHandle = fopen(m_Filename.c_str(), "rb"); break;
|
||||||
case 0x02: //m_pFileHandle = fopen(m_Filename.c_str(), "wb"); break;
|
case 0x02: //m_pFileHandle = fopen(m_Filename.c_str(), "wb"); break;
|
||||||
case 0x03: m_pFileHandle = fopen(m_Filename.c_str(), "r+b"); break;
|
case 0x03: m_pFileHandle = fopen(m_Filename.c_str(), "r+b"); break;
|
||||||
default: PanicAlert("CWII_IPC_HLE_Device_FileIO: unknown open mode"); break;
|
default: PanicAlert("CWII_IPC_HLE_Device_FileIO: unknown open mode"); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ReturnValue = 0;
|
u32 ReturnValue = 0;
|
||||||
if (m_pFileHandle != NULL)
|
if (m_pFileHandle != NULL)
|
||||||
{
|
{
|
||||||
m_FileLength = File::GetSize(m_Filename.c_str());
|
m_FileLength = File::GetSize(m_Filename.c_str());
|
||||||
ReturnValue = GetDeviceID();
|
ReturnValue = GetDeviceID();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, " failed - File doesn't exist");
|
LOG(WII_IPC_FILEIO, " failed - File doesn't exist");
|
||||||
ReturnValue = -106;
|
ReturnValue = -106;
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress+4);
|
Memory::Write_U32(ReturnValue, _CommandAddress+4);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
u32 ReturnValue = 0;
|
u32 ReturnValue = 0;
|
||||||
u32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
|
u32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
|
||||||
u32 Mode = Memory::Read_U32(_CommandAddress +0x10);
|
u32 Mode = Memory::Read_U32(_CommandAddress +0x10);
|
||||||
|
|
||||||
LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: %i, Mode: %i (Device=%s)", SeekPosition, Mode, GetDeviceName().c_str());
|
LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: %i, Mode: %i (Device=%s)", SeekPosition, Mode, GetDeviceName().c_str());
|
||||||
|
|
||||||
switch(Mode)
|
switch(Mode)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
if (fseek(m_pFileHandle, SeekPosition, SEEK_SET) == 0) {
|
if (fseek(m_pFileHandle, SeekPosition, SEEK_SET) == 0) {
|
||||||
// Seek always return the seek position for success
|
// Seek always return the seek position for success
|
||||||
ReturnValue = SeekPosition;
|
ReturnValue = SeekPosition;
|
||||||
} else {
|
} else {
|
||||||
LOG(WII_IPC_FILEIO, "FILEIO: Seek failed");
|
LOG(WII_IPC_FILEIO, "FILEIO: Seek failed");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: // cur
|
case 1: // cur
|
||||||
case 2: // end
|
case 2: // end
|
||||||
default:
|
default:
|
||||||
PanicAlert("CWII_IPC_HLE_Device_FileIO unsupported seek mode");
|
PanicAlert("CWII_IPC_HLE_Device_FileIO unsupported seek mode");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
|
CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
u32 ReturnValue = 0;
|
u32 ReturnValue = 0;
|
||||||
u32 Address = Memory::Read_U32(_CommandAddress +0xC);
|
u32 Address = Memory::Read_U32(_CommandAddress +0xC);
|
||||||
u32 Size = Memory::Read_U32(_CommandAddress +0x10);
|
u32 Size = Memory::Read_U32(_CommandAddress +0x10);
|
||||||
|
|
||||||
if (m_pFileHandle != NULL)
|
if (m_pFileHandle != NULL)
|
||||||
{
|
{
|
||||||
size_t readItems = fread(Memory::GetPointer(Address), 1, Size, m_pFileHandle);
|
size_t readItems = fread(Memory::GetPointer(Address), 1, Size, m_pFileHandle);
|
||||||
ReturnValue = (u32)readItems;
|
ReturnValue = (u32)readItems;
|
||||||
LOG(WII_IPC_FILEIO, "FileIO reads from %s (Addr=0x%08x Size=0x%x)", GetDeviceName().c_str(), Address, Size);
|
LOG(WII_IPC_FILEIO, "FileIO reads from %s (Addr=0x%08x Size=0x%x)", GetDeviceName().c_str(), Address, Size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "FileIO failed to read from %s (Addr=0x%08x Size=0x%x) - file not open", GetDeviceName().c_str(), Address, Size);
|
LOG(WII_IPC_FILEIO, "FileIO failed to read from %s (Addr=0x%08x Size=0x%x) - file not open", GetDeviceName().c_str(), Address, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
|
CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
u32 ReturnValue = 0;
|
u32 ReturnValue = 0;
|
||||||
u32 Address = Memory::Read_U32(_CommandAddress +0xC);
|
u32 Address = Memory::Read_U32(_CommandAddress +0xC);
|
||||||
u32 Size = Memory::Read_U32(_CommandAddress +0x10);
|
u32 Size = Memory::Read_U32(_CommandAddress +0x10);
|
||||||
|
|
||||||
LOG(WII_IPC_FILEIO, "FileIO: Write Addr: 0x%08x Size: %i (Device=%s)", Address, Size, GetDeviceName().c_str());
|
LOG(WII_IPC_FILEIO, "FileIO: Write Addr: 0x%08x Size: %i (Device=%s)", Address, Size, GetDeviceName().c_str());
|
||||||
|
|
||||||
if (m_pFileHandle)
|
if (m_pFileHandle)
|
||||||
{
|
{
|
||||||
fwrite(Memory::GetPointer(Address), Size, 1, m_pFileHandle);
|
fwrite(Memory::GetPointer(Address), Size, 1, m_pFileHandle);
|
||||||
|
|
||||||
// Write always return the written bytes for success
|
// Write always return the written bytes for success
|
||||||
ReturnValue = Size;
|
ReturnValue = Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
|
CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "FileIO: IOCtl (Device=%s)", GetDeviceName().c_str());
|
LOG(WII_IPC_FILEIO, "FileIO: IOCtl (Device=%s)", GetDeviceName().c_str());
|
||||||
DumpCommands(_CommandAddress);
|
DumpCommands(_CommandAddress);
|
||||||
|
|
||||||
u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
|
u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
|
||||||
|
|
||||||
// u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
// u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
||||||
// u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
// u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
||||||
// u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
// u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||||
// u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
// u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
||||||
|
|
||||||
switch(Parameter)
|
switch(Parameter)
|
||||||
{
|
{
|
||||||
case ISFS_IOCTL_GETFILESTATS:
|
case ISFS_IOCTL_GETFILESTATS:
|
||||||
{
|
{
|
||||||
u32 Position = (u32)ftell(m_pFileHandle);
|
u32 Position = (u32)ftell(m_pFileHandle);
|
||||||
|
|
||||||
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||||
LOG(WII_IPC_FILEIO, "FileIO: ISFS_IOCTL_GETFILESTATS");
|
LOG(WII_IPC_FILEIO, "FileIO: ISFS_IOCTL_GETFILESTATS");
|
||||||
LOG(WII_IPC_FILEIO, " Length: %i Seek: %i", m_FileLength, Position);
|
LOG(WII_IPC_FILEIO, " Length: %i Seek: %i", m_FileLength, Position);
|
||||||
|
|
||||||
Memory::Write_U32((u32)m_FileLength, BufferOut);
|
Memory::Write_U32((u32)m_FileLength, BufferOut);
|
||||||
Memory::Write_U32(Position, BufferOut+4);
|
Memory::Write_U32(Position, BufferOut+4);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
PanicAlert("CWII_IPC_HLE_Device_FileIO: Parameter %i", Parameter);
|
PanicAlert("CWII_IPC_HLE_Device_FileIO: Parameter %i", Parameter);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return Value
|
// Return Value
|
||||||
u32 ReturnValue = 0; // no error
|
u32 ReturnValue = 0; // no error
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CWII_IPC_HLE_Device_FileIO::ReturnFileHandle()
|
CWII_IPC_HLE_Device_FileIO::ReturnFileHandle()
|
||||||
{
|
{
|
||||||
if(m_pFileHandle == NULL)
|
if(m_pFileHandle == NULL)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,499 +1,499 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
#include "WII_IPC_HLE_Device_fs.h"
|
#include "WII_IPC_HLE_Device_fs.h"
|
||||||
|
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "FileSearch.h"
|
#include "FileSearch.h"
|
||||||
#include "FileUtil.h"
|
#include "FileUtil.h"
|
||||||
|
|
||||||
#include "../VolumeHandler.h"
|
#include "../VolumeHandler.h"
|
||||||
|
|
||||||
extern std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size);
|
extern std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size);
|
||||||
|
|
||||||
#define FS_RESULT_OK (0)
|
#define FS_RESULT_OK (0)
|
||||||
#define FS_DIRFILE_NOT_FOUND (-6)
|
#define FS_DIRFILE_NOT_FOUND (-6)
|
||||||
#define FS_INVALID_ARGUMENT (-101)
|
#define FS_INVALID_ARGUMENT (-101)
|
||||||
#define FS_FILE_EXIST (-105)
|
#define FS_FILE_EXIST (-105)
|
||||||
#define FS_FILE_NOT_EXIST (-106)
|
#define FS_FILE_NOT_EXIST (-106)
|
||||||
#define FS_RESULT_FATAL (-128)
|
#define FS_RESULT_FATAL (-128)
|
||||||
|
|
||||||
#define MAX_NAME (12)
|
#define MAX_NAME (12)
|
||||||
|
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_fs::CWII_IPC_HLE_Device_fs(u32 _DeviceID, const std::string& _rDeviceName)
|
CWII_IPC_HLE_Device_fs::CWII_IPC_HLE_Device_fs(u32 _DeviceID, const std::string& _rDeviceName)
|
||||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_fs::~CWII_IPC_HLE_Device_fs()
|
CWII_IPC_HLE_Device_fs::~CWII_IPC_HLE_Device_fs()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_fs::Open(u32 _CommandAddress, u32 _Mode)
|
bool CWII_IPC_HLE_Device_fs::Open(u32 _CommandAddress, u32 _Mode)
|
||||||
{
|
{
|
||||||
// clear tmp folder
|
// clear tmp folder
|
||||||
{
|
{
|
||||||
std::string WiiTempFolder(FULL_WII_USER_DIR "tmp");
|
std::string WiiTempFolder(FULL_WII_USER_DIR "tmp");
|
||||||
File::DeleteDirRecursively(WiiTempFolder.c_str());
|
File::DeleteDirRecursively(WiiTempFolder.c_str());
|
||||||
File::CreateDir(WiiTempFolder.c_str());
|
File::CreateDir(WiiTempFolder.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// create home directory
|
// create home directory
|
||||||
{
|
{
|
||||||
u32 TitleID = VolumeHandler::Read32(0);
|
u32 TitleID = VolumeHandler::Read32(0);
|
||||||
if (TitleID == 0) TitleID = 0xF00DBEEF;
|
if (TitleID == 0) TitleID = 0xF00DBEEF;
|
||||||
|
|
||||||
char* pTitleID = (char*)&TitleID;
|
char* pTitleID = (char*)&TitleID;
|
||||||
|
|
||||||
char Path[260+1];
|
char Path[260+1];
|
||||||
sprintf(Path, FULL_WII_USER_DIR "title/00010000/%02x%02x%02x%02x/data/nocopy/",
|
sprintf(Path, FULL_WII_USER_DIR "title/00010000/%02x%02x%02x%02x/data/nocopy/",
|
||||||
(u8)pTitleID[3], (u8)pTitleID[2], (u8)pTitleID[1], (u8)pTitleID[0]);
|
(u8)pTitleID[3], (u8)pTitleID[2], (u8)pTitleID[1], (u8)pTitleID[0]);
|
||||||
|
|
||||||
File::CreateDirectoryStructure(Path);
|
File::CreateDirectoryStructure(Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
|
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// IOCtlV calls begin here
|
// IOCtlV calls begin here
|
||||||
// -------------
|
// -------------
|
||||||
bool CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress)
|
bool CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
u32 ReturnValue = FS_RESULT_OK;
|
u32 ReturnValue = FS_RESULT_OK;
|
||||||
SIOCtlVBuffer CommandBuffer(_CommandAddress);
|
SIOCtlVBuffer CommandBuffer(_CommandAddress);
|
||||||
|
|
||||||
// Prepare the out buffer(s) with zeroes as a safety precaution
|
// Prepare the out buffer(s) with zeroes as a safety precaution
|
||||||
// to avoid returning bad values
|
// to avoid returning bad values
|
||||||
for(u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; i++)
|
for(u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; i++)
|
||||||
{
|
{
|
||||||
Memory::Memset(CommandBuffer.PayloadBuffer[i].m_Address, 0,
|
Memory::Memset(CommandBuffer.PayloadBuffer[i].m_Address, 0,
|
||||||
CommandBuffer.PayloadBuffer[i].m_Size);
|
CommandBuffer.PayloadBuffer[i].m_Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(CommandBuffer.Parameter)
|
switch(CommandBuffer.Parameter)
|
||||||
{
|
{
|
||||||
case IOCTL_READ_DIR:
|
case IOCTL_READ_DIR:
|
||||||
{
|
{
|
||||||
// the wii uses this function to define the type (dir or file)
|
// the wii uses this function to define the type (dir or file)
|
||||||
std::string Filename(HLE_IPC_BuildFilename((const char*)Memory::GetPointer(
|
std::string Filename(HLE_IPC_BuildFilename((const char*)Memory::GetPointer(
|
||||||
CommandBuffer.InBuffer[0].m_Address), CommandBuffer.InBuffer[0].m_Size));
|
CommandBuffer.InBuffer[0].m_Address), CommandBuffer.InBuffer[0].m_Size));
|
||||||
|
|
||||||
LOG(WII_IPC_FILEIO, "FS: IOCTL_READ_DIR %s", Filename.c_str());
|
LOG(WII_IPC_FILEIO, "FS: IOCTL_READ_DIR %s", Filename.c_str());
|
||||||
|
|
||||||
/* Check if this is really a directory. Or a file, because it seems like Mario Kart
|
/* Check if this is really a directory. Or a file, because it seems like Mario Kart
|
||||||
did a IOCTL_READ_DIR on the save file to check if it existed before deleting it,
|
did a IOCTL_READ_DIR on the save file to check if it existed before deleting it,
|
||||||
and if I didn't returned a -something it never deleted the file presumably because
|
and if I didn't returned a -something it never deleted the file presumably because
|
||||||
it thought it didn't exist. So this solution worked for Mario Kart.
|
it thought it didn't exist. So this solution worked for Mario Kart.
|
||||||
|
|
||||||
F|RES: i dont have mkart but -6 is a wrong return value if you try to read from a
|
F|RES: i dont have mkart but -6 is a wrong return value if you try to read from a
|
||||||
directory which doesnt exist
|
directory which doesnt exist
|
||||||
|
|
||||||
JP: Okay, but Mario Kart calls this for files and if I return 0 here it never
|
JP: Okay, but Mario Kart calls this for files and if I return 0 here it never
|
||||||
creates a new file in any event, it just calls a DELETE_FILE and never close
|
creates a new file in any event, it just calls a DELETE_FILE and never close
|
||||||
the handle, so perhaps this is better
|
the handle, so perhaps this is better
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!File::Exists(Filename.c_str()))
|
if (!File::Exists(Filename.c_str()))
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, " directory does not exist - return FS_DIRFILE_NOT_FOUND", Filename.c_str());
|
LOG(WII_IPC_FILEIO, " directory does not exist - return FS_DIRFILE_NOT_FOUND", Filename.c_str());
|
||||||
ReturnValue = FS_DIRFILE_NOT_FOUND;
|
ReturnValue = FS_DIRFILE_NOT_FOUND;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Okay, maybe it is a file but not a directory, then we should return -101?
|
/* Okay, maybe it is a file but not a directory, then we should return -101?
|
||||||
I have not seen any example of this. */
|
I have not seen any example of this. */
|
||||||
else if (!File::IsDirectory(Filename.c_str()))
|
else if (!File::IsDirectory(Filename.c_str()))
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, " Not a directory - return FS_INVALID_ARGUMENT", Filename.c_str());
|
LOG(WII_IPC_FILEIO, " Not a directory - return FS_INVALID_ARGUMENT", Filename.c_str());
|
||||||
ReturnValue = FS_INVALID_ARGUMENT;
|
ReturnValue = FS_INVALID_ARGUMENT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a file search
|
// make a file search
|
||||||
CFileSearch::XStringVector Directories;
|
CFileSearch::XStringVector Directories;
|
||||||
Directories.push_back(Filename);
|
Directories.push_back(Filename);
|
||||||
|
|
||||||
CFileSearch::XStringVector Extensions;
|
CFileSearch::XStringVector Extensions;
|
||||||
Extensions.push_back("*.*");
|
Extensions.push_back("*.*");
|
||||||
|
|
||||||
CFileSearch FileSearch(Extensions, Directories);
|
CFileSearch FileSearch(Extensions, Directories);
|
||||||
|
|
||||||
// it is one
|
// it is one
|
||||||
if ((CommandBuffer.InBuffer.size() == 1) && (CommandBuffer.PayloadBuffer.size() == 1))
|
if ((CommandBuffer.InBuffer.size() == 1) && (CommandBuffer.PayloadBuffer.size() == 1))
|
||||||
{
|
{
|
||||||
size_t numFile = FileSearch.GetFileNames().size();
|
size_t numFile = FileSearch.GetFileNames().size();
|
||||||
LOG(WII_IPC_FILEIO, " Files in directory: %i", numFile);
|
LOG(WII_IPC_FILEIO, " Files in directory: %i", numFile);
|
||||||
|
|
||||||
Memory::Write_U32((u32)numFile, CommandBuffer.PayloadBuffer[0].m_Address);
|
Memory::Write_U32((u32)numFile, CommandBuffer.PayloadBuffer[0].m_Address);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 MaxEntries = Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address);
|
u32 MaxEntries = Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address);
|
||||||
|
|
||||||
memset(Memory::GetPointer(CommandBuffer.PayloadBuffer[0].m_Address), 0, CommandBuffer.PayloadBuffer[0].m_Size);
|
memset(Memory::GetPointer(CommandBuffer.PayloadBuffer[0].m_Address), 0, CommandBuffer.PayloadBuffer[0].m_Size);
|
||||||
|
|
||||||
size_t numFiles = 0;
|
size_t numFiles = 0;
|
||||||
char* pFilename = (char*)Memory::GetPointer((u32)(CommandBuffer.PayloadBuffer[0].m_Address));
|
char* pFilename = (char*)Memory::GetPointer((u32)(CommandBuffer.PayloadBuffer[0].m_Address));
|
||||||
|
|
||||||
for (size_t i=0; i<FileSearch.GetFileNames().size(); i++)
|
for (size_t i=0; i<FileSearch.GetFileNames().size(); i++)
|
||||||
{
|
{
|
||||||
if (i >= MaxEntries)
|
if (i >= MaxEntries)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
std::string filename, ext;
|
std::string filename, ext;
|
||||||
SplitPath(FileSearch.GetFileNames()[i], NULL, &filename, &ext);
|
SplitPath(FileSearch.GetFileNames()[i], NULL, &filename, &ext);
|
||||||
std::string CompleteFilename = filename + ext;
|
std::string CompleteFilename = filename + ext;
|
||||||
|
|
||||||
strcpy(pFilename, CompleteFilename.c_str());
|
strcpy(pFilename, CompleteFilename.c_str());
|
||||||
pFilename += CompleteFilename.length();
|
pFilename += CompleteFilename.length();
|
||||||
*pFilename++ = 0x00; // termination
|
*pFilename++ = 0x00; // termination
|
||||||
numFiles++;
|
numFiles++;
|
||||||
|
|
||||||
LOG(WII_IPC_FILEIO, " %s", CompleteFilename.c_str());
|
LOG(WII_IPC_FILEIO, " %s", CompleteFilename.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::Write_U32((u32)numFiles, CommandBuffer.PayloadBuffer[1].m_Address);
|
Memory::Write_U32((u32)numFiles, CommandBuffer.PayloadBuffer[1].m_Address);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue = FS_RESULT_OK;
|
ReturnValue = FS_RESULT_OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IOCTL_GETUSAGE:
|
case IOCTL_GETUSAGE:
|
||||||
{
|
{
|
||||||
// check buffer sizes
|
// check buffer sizes
|
||||||
_dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer.size() == 2);
|
_dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer.size() == 2);
|
||||||
_dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[0].m_Size == 4);
|
_dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[0].m_Size == 4);
|
||||||
_dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[1].m_Size == 4);
|
_dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[1].m_Size == 4);
|
||||||
|
|
||||||
// this command sucks because it asks of the number of used
|
// this command sucks because it asks of the number of used
|
||||||
// fsBlocks and inodes
|
// fsBlocks and inodes
|
||||||
// we answer nothing is used, but if a program uses it to check
|
// we answer nothing is used, but if a program uses it to check
|
||||||
// how much memory has been used we are doomed...
|
// how much memory has been used we are doomed...
|
||||||
std::string Filename(HLE_IPC_BuildFilename((const char*)Memory::GetPointer(CommandBuffer.InBuffer[0].m_Address), CommandBuffer.InBuffer[0].m_Size));
|
std::string Filename(HLE_IPC_BuildFilename((const char*)Memory::GetPointer(CommandBuffer.InBuffer[0].m_Address), CommandBuffer.InBuffer[0].m_Size));
|
||||||
u32 fsBlock = 0;
|
u32 fsBlock = 0;
|
||||||
u32 iNodes = 0;
|
u32 iNodes = 0;
|
||||||
|
|
||||||
LOGV(WII_IPC_FILEIO, 1, "FS: IOCTL_GETUSAGE %s", Filename.c_str());
|
LOGV(WII_IPC_FILEIO, 1, "FS: IOCTL_GETUSAGE %s", Filename.c_str());
|
||||||
if (File::IsDirectory(Filename.c_str()))
|
if (File::IsDirectory(Filename.c_str()))
|
||||||
{
|
{
|
||||||
// make a file search
|
// make a file search
|
||||||
CFileSearch::XStringVector Directories;
|
CFileSearch::XStringVector Directories;
|
||||||
Directories.push_back(Filename);
|
Directories.push_back(Filename);
|
||||||
|
|
||||||
CFileSearch::XStringVector Extensions;
|
CFileSearch::XStringVector Extensions;
|
||||||
Extensions.push_back("*.*");
|
Extensions.push_back("*.*");
|
||||||
|
|
||||||
CFileSearch FileSearch(Extensions, Directories);
|
CFileSearch FileSearch(Extensions, Directories);
|
||||||
|
|
||||||
u64 overAllSize = 0;
|
u64 overAllSize = 0;
|
||||||
for (size_t i=0; i<FileSearch.GetFileNames().size(); i++)
|
for (size_t i=0; i<FileSearch.GetFileNames().size(); i++)
|
||||||
{
|
{
|
||||||
overAllSize += File::GetSize(FileSearch.GetFileNames()[i].c_str());
|
overAllSize += File::GetSize(FileSearch.GetFileNames()[i].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
fsBlock = (u32)(overAllSize / (16 * 1024)); // one bock is 16kb
|
fsBlock = (u32)(overAllSize / (16 * 1024)); // one bock is 16kb
|
||||||
iNodes = (u32)(FileSearch.GetFileNames().size());
|
iNodes = (u32)(FileSearch.GetFileNames().size());
|
||||||
|
|
||||||
ReturnValue = FS_RESULT_OK;
|
ReturnValue = FS_RESULT_OK;
|
||||||
|
|
||||||
LOGV(WII_IPC_FILEIO, 1, " fsBlock: %i, iNodes: %i", fsBlock, iNodes);
|
LOGV(WII_IPC_FILEIO, 1, " fsBlock: %i, iNodes: %i", fsBlock, iNodes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fsBlock = 0;
|
fsBlock = 0;
|
||||||
iNodes = 0;
|
iNodes = 0;
|
||||||
ReturnValue = FS_RESULT_OK;
|
ReturnValue = FS_RESULT_OK;
|
||||||
|
|
||||||
// PanicAlert("IOCTL_GETUSAGE - unk dir %s", Filename.c_str());
|
// PanicAlert("IOCTL_GETUSAGE - unk dir %s", Filename.c_str());
|
||||||
LOGV(WII_IPC_FILEIO, 1, " error: not executed on a valid directoy: %s", Filename.c_str());
|
LOGV(WII_IPC_FILEIO, 1, " error: not executed on a valid directoy: %s", Filename.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::Write_U32(fsBlock, CommandBuffer.PayloadBuffer[0].m_Address);
|
Memory::Write_U32(fsBlock, CommandBuffer.PayloadBuffer[0].m_Address);
|
||||||
Memory::Write_U32(iNodes, CommandBuffer.PayloadBuffer[1].m_Address);
|
Memory::Write_U32(iNodes, CommandBuffer.PayloadBuffer[1].m_Address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PanicAlert("CWII_IPC_HLE_Device_fs::IOCtlV: %i", CommandBuffer.Parameter);
|
PanicAlert("CWII_IPC_HLE_Device_fs::IOCtlV: %i", CommandBuffer.Parameter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress+4);
|
Memory::Write_U32(ReturnValue, _CommandAddress+4);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// IOCtl calls begin here
|
// IOCtl calls begin here
|
||||||
// -------------
|
// -------------
|
||||||
bool CWII_IPC_HLE_Device_fs::IOCtl(u32 _CommandAddress)
|
bool CWII_IPC_HLE_Device_fs::IOCtl(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
//u32 DeviceID = Memory::Read_U32(_CommandAddress + 8);
|
//u32 DeviceID = Memory::Read_U32(_CommandAddress + 8);
|
||||||
//LOG(WII_IPC_FILEIO, "FS: IOCtl (Device=%s, DeviceID=%08x)", GetDeviceName().c_str(), DeviceID);
|
//LOG(WII_IPC_FILEIO, "FS: IOCtl (Device=%s, DeviceID=%08x)", GetDeviceName().c_str(), DeviceID);
|
||||||
|
|
||||||
u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
|
u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
|
||||||
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
||||||
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
||||||
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||||
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
||||||
|
|
||||||
/* Prepare the out buffer(s) with zeroes as a safety precaution
|
/* Prepare the out buffer(s) with zeroes as a safety precaution
|
||||||
to avoid returning bad values. */
|
to avoid returning bad values. */
|
||||||
//LOG(WII_IPC_FILEIO, "Cleared %u bytes of the out buffer", _BufferOutSize);
|
//LOG(WII_IPC_FILEIO, "Cleared %u bytes of the out buffer", _BufferOutSize);
|
||||||
Memory::Memset(BufferOut, 0, BufferOutSize);
|
Memory::Memset(BufferOut, 0, BufferOutSize);
|
||||||
|
|
||||||
u32 ReturnValue = ExecuteCommand(Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
u32 ReturnValue = ExecuteCommand(Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress + 4);
|
Memory::Write_U32(ReturnValue, _CommandAddress + 4);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// Execute IOCtl commands
|
// Execute IOCtl commands
|
||||||
// -------------
|
// -------------
|
||||||
s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize)
|
s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize)
|
||||||
{
|
{
|
||||||
switch(_Parameter)
|
switch(_Parameter)
|
||||||
{
|
{
|
||||||
case GET_STATS:
|
case GET_STATS:
|
||||||
{
|
{
|
||||||
_dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 28);
|
_dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 28);
|
||||||
|
|
||||||
LOG(WII_IPC_FILEIO, "FS: GET STATS - no idea what we have to return here, prolly the free memory etc:)");
|
LOG(WII_IPC_FILEIO, "FS: GET STATS - no idea what we have to return here, prolly the free memory etc:)");
|
||||||
LOG(WII_IPC_FILEIO, " InBufferSize: %i OutBufferSize: %i", _BufferInSize, _BufferOutSize);
|
LOG(WII_IPC_FILEIO, " InBufferSize: %i OutBufferSize: %i", _BufferInSize, _BufferOutSize);
|
||||||
PanicAlert("GET_STATS");
|
PanicAlert("GET_STATS");
|
||||||
|
|
||||||
/* Memory::Write_U32(Addr, a); Addr += 4;
|
/* Memory::Write_U32(Addr, a); Addr += 4;
|
||||||
Memory::Write_U32(Addr, b); Addr += 4;
|
Memory::Write_U32(Addr, b); Addr += 4;
|
||||||
Memory::Write_U32(Addr, c); Addr += 4;
|
Memory::Write_U32(Addr, c); Addr += 4;
|
||||||
Memory::Write_U32(Addr, d); Addr += 4;
|
Memory::Write_U32(Addr, d); Addr += 4;
|
||||||
Memory::Write_U32(Addr, e); Addr += 4;
|
Memory::Write_U32(Addr, e); Addr += 4;
|
||||||
Memory::Write_U32(Addr, f); Addr += 4;
|
Memory::Write_U32(Addr, f); Addr += 4;
|
||||||
Memory::Write_U32(Addr, g); Addr += 4;
|
Memory::Write_U32(Addr, g); Addr += 4;
|
||||||
*/
|
*/
|
||||||
return FS_RESULT_OK;
|
return FS_RESULT_OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CREATE_DIR:
|
case CREATE_DIR:
|
||||||
{
|
{
|
||||||
_dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);
|
_dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);
|
||||||
u32 Addr = _BufferIn;
|
u32 Addr = _BufferIn;
|
||||||
|
|
||||||
u32 OwnerID = Memory::Read_U32(Addr); Addr += 4;
|
u32 OwnerID = Memory::Read_U32(Addr); Addr += 4;
|
||||||
u16 GroupID = Memory::Read_U16(Addr); Addr += 2;
|
u16 GroupID = Memory::Read_U16(Addr); Addr += 2;
|
||||||
std::string DirName(HLE_IPC_BuildFilename((const char*)Memory::GetPointer(Addr), 64)); Addr += 64;
|
std::string DirName(HLE_IPC_BuildFilename((const char*)Memory::GetPointer(Addr), 64)); Addr += 64;
|
||||||
Addr += 9; // owner attribs, permission
|
Addr += 9; // owner attribs, permission
|
||||||
u8 Attribs = Memory::Read_U8(Addr);
|
u8 Attribs = Memory::Read_U8(Addr);
|
||||||
|
|
||||||
LOG(WII_IPC_FILEIO, "FS: CREATE_DIR %s", DirName.c_str());
|
LOG(WII_IPC_FILEIO, "FS: CREATE_DIR %s", DirName.c_str());
|
||||||
|
|
||||||
DirName += DIR_SEP;
|
DirName += DIR_SEP;
|
||||||
File::CreateDirectoryStructure(DirName );
|
File::CreateDirectoryStructure(DirName );
|
||||||
_dbg_assert_msg_(WII_IPC_FILEIO, File::IsDirectory(DirName.c_str()), "FS: CREATE_DIR %s failed", DirName.c_str());
|
_dbg_assert_msg_(WII_IPC_FILEIO, File::IsDirectory(DirName.c_str()), "FS: CREATE_DIR %s failed", DirName.c_str());
|
||||||
|
|
||||||
return FS_RESULT_OK;
|
return FS_RESULT_OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SET_ATTR:
|
case SET_ATTR:
|
||||||
{
|
{
|
||||||
u32 Addr = _BufferIn;
|
u32 Addr = _BufferIn;
|
||||||
|
|
||||||
u32 OwnerID = Memory::Read_U32(Addr); Addr += 4;
|
u32 OwnerID = Memory::Read_U32(Addr); Addr += 4;
|
||||||
u16 GroupID = Memory::Read_U16(Addr); Addr += 2;
|
u16 GroupID = Memory::Read_U16(Addr); Addr += 2;
|
||||||
std::string Filename = HLE_IPC_BuildFilename((const char*)Memory::GetPointer(_BufferIn), 64); Addr += 64;
|
std::string Filename = HLE_IPC_BuildFilename((const char*)Memory::GetPointer(_BufferIn), 64); Addr += 64;
|
||||||
u8 OwnerPerm = Memory::Read_U8(Addr); Addr += 1;
|
u8 OwnerPerm = Memory::Read_U8(Addr); Addr += 1;
|
||||||
u8 GroupPerm = Memory::Read_U8(Addr); Addr += 1;
|
u8 GroupPerm = Memory::Read_U8(Addr); Addr += 1;
|
||||||
u8 OtherPerm = Memory::Read_U8(Addr); Addr += 1;
|
u8 OtherPerm = Memory::Read_U8(Addr); Addr += 1;
|
||||||
u8 Attributes = Memory::Read_U8(Addr); Addr += 1;
|
u8 Attributes = Memory::Read_U8(Addr); Addr += 1;
|
||||||
|
|
||||||
LOGV(WII_IPC_FILEIO, 0, "FS: SetAttrib %s", Filename.c_str());
|
LOGV(WII_IPC_FILEIO, 0, "FS: SetAttrib %s", Filename.c_str());
|
||||||
LOG(WII_IPC_FILEIO, " OwnerID: 0x%08x", OwnerID);
|
LOG(WII_IPC_FILEIO, " OwnerID: 0x%08x", OwnerID);
|
||||||
LOG(WII_IPC_FILEIO, " GroupID: 0x%04x", GroupID);
|
LOG(WII_IPC_FILEIO, " GroupID: 0x%04x", GroupID);
|
||||||
LOG(WII_IPC_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm);
|
LOG(WII_IPC_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm);
|
||||||
LOG(WII_IPC_FILEIO, " GroupPerm: 0x%02x", GroupPerm);
|
LOG(WII_IPC_FILEIO, " GroupPerm: 0x%02x", GroupPerm);
|
||||||
LOG(WII_IPC_FILEIO, " OtherPerm: 0x%02x", OtherPerm);
|
LOG(WII_IPC_FILEIO, " OtherPerm: 0x%02x", OtherPerm);
|
||||||
LOG(WII_IPC_FILEIO, " Attributes: 0x%02x", Attributes);
|
LOG(WII_IPC_FILEIO, " Attributes: 0x%02x", Attributes);
|
||||||
|
|
||||||
return FS_RESULT_OK;
|
return FS_RESULT_OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GET_ATTR:
|
case GET_ATTR:
|
||||||
{
|
{
|
||||||
_dbg_assert_msg_(WII_IPC_FILEIO, _BufferOutSize == 76,
|
_dbg_assert_msg_(WII_IPC_FILEIO, _BufferOutSize == 76,
|
||||||
" GET_ATTR needs an 76 bytes large output buffer but it is %i bytes large",
|
" GET_ATTR needs an 76 bytes large output buffer but it is %i bytes large",
|
||||||
_BufferOutSize);
|
_BufferOutSize);
|
||||||
|
|
||||||
u32 OwnerID = 0;
|
u32 OwnerID = 0;
|
||||||
u16 GroupID = 0;
|
u16 GroupID = 0;
|
||||||
std::string Filename = HLE_IPC_BuildFilename((const char*)Memory::GetPointer(_BufferIn), 64);
|
std::string Filename = HLE_IPC_BuildFilename((const char*)Memory::GetPointer(_BufferIn), 64);
|
||||||
u8 OwnerPerm = 0x3; // read/write
|
u8 OwnerPerm = 0x3; // read/write
|
||||||
u8 GroupPerm = 0x3; // read/write
|
u8 GroupPerm = 0x3; // read/write
|
||||||
u8 OtherPerm = 0x3; // read/write
|
u8 OtherPerm = 0x3; // read/write
|
||||||
u8 Attributes = 0x00; // no attributes
|
u8 Attributes = 0x00; // no attributes
|
||||||
if (File::IsDirectory(Filename.c_str()))
|
if (File::IsDirectory(Filename.c_str()))
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "FS: GET_ATTR Directory %s - all permission flags are set", Filename.c_str());
|
LOG(WII_IPC_FILEIO, "FS: GET_ATTR Directory %s - all permission flags are set", Filename.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (File::Exists(Filename.c_str()))
|
if (File::Exists(Filename.c_str()))
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "FS: GET_ATTR %s - all permission flags are set", Filename.c_str());
|
LOG(WII_IPC_FILEIO, "FS: GET_ATTR %s - all permission flags are set", Filename.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "FS: GET_ATTR unknown %s", Filename.c_str());
|
LOG(WII_IPC_FILEIO, "FS: GET_ATTR unknown %s", Filename.c_str());
|
||||||
return FS_FILE_NOT_EXIST;
|
return FS_FILE_NOT_EXIST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// write answer to buffer
|
// write answer to buffer
|
||||||
if (_BufferOutSize == 76)
|
if (_BufferOutSize == 76)
|
||||||
{
|
{
|
||||||
u32 Addr = _BufferOut;
|
u32 Addr = _BufferOut;
|
||||||
Memory::Write_U32(OwnerID, Addr); Addr += 4;
|
Memory::Write_U32(OwnerID, Addr); Addr += 4;
|
||||||
Memory::Write_U16(GroupID, Addr); Addr += 2;
|
Memory::Write_U16(GroupID, Addr); Addr += 2;
|
||||||
memcpy(Memory::GetPointer(Addr), Filename.c_str(), Filename.size()); Addr += 64;
|
memcpy(Memory::GetPointer(Addr), Filename.c_str(), Filename.size()); Addr += 64;
|
||||||
Memory::Write_U8(OwnerPerm, Addr); Addr += 1;
|
Memory::Write_U8(OwnerPerm, Addr); Addr += 1;
|
||||||
Memory::Write_U8(GroupPerm, Addr); Addr += 1;
|
Memory::Write_U8(GroupPerm, Addr); Addr += 1;
|
||||||
Memory::Write_U8(OtherPerm, Addr); Addr += 1;
|
Memory::Write_U8(OtherPerm, Addr); Addr += 1;
|
||||||
Memory::Write_U8(Attributes, Addr); Addr += 1;
|
Memory::Write_U8(Attributes, Addr); Addr += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FS_RESULT_OK;
|
return FS_RESULT_OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case DELETE_FILE:
|
case DELETE_FILE:
|
||||||
{
|
{
|
||||||
_dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);
|
_dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);
|
||||||
int Offset = 0;
|
int Offset = 0;
|
||||||
|
|
||||||
std::string Filename = HLE_IPC_BuildFilename((const char*)Memory::GetPointer(_BufferIn+Offset), 64);
|
std::string Filename = HLE_IPC_BuildFilename((const char*)Memory::GetPointer(_BufferIn+Offset), 64);
|
||||||
Offset += 64;
|
Offset += 64;
|
||||||
if (File::Delete(Filename.c_str()))
|
if (File::Delete(Filename.c_str()))
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "FS: DeleteFile %s", Filename.c_str());
|
LOG(WII_IPC_FILEIO, "FS: DeleteFile %s", Filename.c_str());
|
||||||
}
|
}
|
||||||
else if (File::DeleteDir(Filename.c_str()))
|
else if (File::DeleteDir(Filename.c_str()))
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "FS: DeleteDir %s", Filename.c_str());
|
LOG(WII_IPC_FILEIO, "FS: DeleteDir %s", Filename.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "FS: DeleteFile %s - failed!!!", Filename.c_str());
|
LOG(WII_IPC_FILEIO, "FS: DeleteFile %s - failed!!!", Filename.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return FS_RESULT_OK;
|
return FS_RESULT_OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RENAME_FILE:
|
case RENAME_FILE:
|
||||||
{
|
{
|
||||||
_dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);
|
_dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);
|
||||||
int Offset = 0;
|
int Offset = 0;
|
||||||
|
|
||||||
std::string Filename = HLE_IPC_BuildFilename((const char*)Memory::GetPointer(_BufferIn+Offset), 64);
|
std::string Filename = HLE_IPC_BuildFilename((const char*)Memory::GetPointer(_BufferIn+Offset), 64);
|
||||||
Offset += 64;
|
Offset += 64;
|
||||||
|
|
||||||
std::string FilenameRename = HLE_IPC_BuildFilename((const char*)Memory::GetPointer(_BufferIn+Offset), 64);
|
std::string FilenameRename = HLE_IPC_BuildFilename((const char*)Memory::GetPointer(_BufferIn+Offset), 64);
|
||||||
Offset += 64;
|
Offset += 64;
|
||||||
|
|
||||||
// try to make the basis directory
|
// try to make the basis directory
|
||||||
File::CreateDirectoryStructure(FilenameRename);
|
File::CreateDirectoryStructure(FilenameRename);
|
||||||
|
|
||||||
// if there is already a filedelete it
|
// if there is already a filedelete it
|
||||||
if (File::Exists(FilenameRename.c_str()))
|
if (File::Exists(FilenameRename.c_str()))
|
||||||
{
|
{
|
||||||
File::Delete(FilenameRename.c_str());
|
File::Delete(FilenameRename.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally try to rename the file
|
// finally try to rename the file
|
||||||
if (File::Rename(Filename.c_str(), FilenameRename.c_str()))
|
if (File::Rename(Filename.c_str(), FilenameRename.c_str()))
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "FS: Rename %s to %s", Filename.c_str(), FilenameRename.c_str());
|
LOG(WII_IPC_FILEIO, "FS: Rename %s to %s", Filename.c_str(), FilenameRename.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, "FS: Rename %s to %s - failed", Filename.c_str(), FilenameRename.c_str());
|
LOG(WII_IPC_FILEIO, "FS: Rename %s to %s - failed", Filename.c_str(), FilenameRename.c_str());
|
||||||
PanicAlert("CWII_IPC_HLE_Device_fs: rename %s to %s failed", Filename.c_str(), FilenameRename.c_str());
|
PanicAlert("CWII_IPC_HLE_Device_fs: rename %s to %s failed", Filename.c_str(), FilenameRename.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return FS_RESULT_OK;
|
return FS_RESULT_OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CREATE_FILE:
|
case CREATE_FILE:
|
||||||
{
|
{
|
||||||
_dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);
|
_dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);
|
||||||
|
|
||||||
u32 Addr = _BufferIn;
|
u32 Addr = _BufferIn;
|
||||||
u32 OwnerID = Memory::Read_U32(Addr); Addr += 4;
|
u32 OwnerID = Memory::Read_U32(Addr); Addr += 4;
|
||||||
u16 GroupID = Memory::Read_U16(Addr); Addr += 2;
|
u16 GroupID = Memory::Read_U16(Addr); Addr += 2;
|
||||||
std::string Filename(HLE_IPC_BuildFilename((const char*)Memory::GetPointer(Addr), 64)); Addr += 64;
|
std::string Filename(HLE_IPC_BuildFilename((const char*)Memory::GetPointer(Addr), 64)); Addr += 64;
|
||||||
u8 OwnerPerm = Memory::Read_U8(Addr); Addr++;
|
u8 OwnerPerm = Memory::Read_U8(Addr); Addr++;
|
||||||
u8 GroupPerm = Memory::Read_U8(Addr); Addr++;
|
u8 GroupPerm = Memory::Read_U8(Addr); Addr++;
|
||||||
u8 OtherPerm = Memory::Read_U8(Addr); Addr++;
|
u8 OtherPerm = Memory::Read_U8(Addr); Addr++;
|
||||||
u8 Attributes = Memory::Read_U8(Addr); Addr++;
|
u8 Attributes = Memory::Read_U8(Addr); Addr++;
|
||||||
|
|
||||||
LOGV(WII_IPC_FILEIO, 0, "FS: CreateFile %s", Filename.c_str());
|
LOGV(WII_IPC_FILEIO, 0, "FS: CreateFile %s", Filename.c_str());
|
||||||
LOG(WII_IPC_FILEIO, " OwnerID: 0x%08x", OwnerID);
|
LOG(WII_IPC_FILEIO, " OwnerID: 0x%08x", OwnerID);
|
||||||
LOG(WII_IPC_FILEIO, " GroupID: 0x%04x", GroupID);
|
LOG(WII_IPC_FILEIO, " GroupID: 0x%04x", GroupID);
|
||||||
LOG(WII_IPC_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm);
|
LOG(WII_IPC_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm);
|
||||||
LOG(WII_IPC_FILEIO, " GroupPerm: 0x%02x", GroupPerm);
|
LOG(WII_IPC_FILEIO, " GroupPerm: 0x%02x", GroupPerm);
|
||||||
LOG(WII_IPC_FILEIO, " OtherPerm: 0x%02x", OtherPerm);
|
LOG(WII_IPC_FILEIO, " OtherPerm: 0x%02x", OtherPerm);
|
||||||
LOG(WII_IPC_FILEIO, " Attributes: 0x%02x", Attributes);
|
LOG(WII_IPC_FILEIO, " Attributes: 0x%02x", Attributes);
|
||||||
|
|
||||||
// check if the file already exist
|
// check if the file already exist
|
||||||
if (File::Exists(Filename.c_str()))
|
if (File::Exists(Filename.c_str()))
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_FILEIO, " result = FS_RESULT_EXISTS", Filename.c_str());
|
LOG(WII_IPC_FILEIO, " result = FS_RESULT_EXISTS", Filename.c_str());
|
||||||
return FS_FILE_EXIST;
|
return FS_FILE_EXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the file
|
// create the file
|
||||||
File::CreateDirectoryStructure(Filename); // just to be sure
|
File::CreateDirectoryStructure(Filename); // just to be sure
|
||||||
bool Result = File::CreateEmptyFile(Filename.c_str());
|
bool Result = File::CreateEmptyFile(Filename.c_str());
|
||||||
if (!Result)
|
if (!Result)
|
||||||
{
|
{
|
||||||
PanicAlert("CWII_IPC_HLE_Device_fs: couldn't create new file");
|
PanicAlert("CWII_IPC_HLE_Device_fs: couldn't create new file");
|
||||||
return FS_RESULT_FATAL;
|
return FS_RESULT_FATAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(WII_IPC_FILEIO, " result = FS_RESULT_OK", Filename.c_str());
|
LOG(WII_IPC_FILEIO, " result = FS_RESULT_OK", Filename.c_str());
|
||||||
return FS_RESULT_OK;
|
return FS_RESULT_OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PanicAlert("CWII_IPC_HLE_Device_fs::IOCtl: ni 0x%x", _Parameter);
|
PanicAlert("CWII_IPC_HLE_Device_fs::IOCtl: ni 0x%x", _Parameter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FS_RESULT_FATAL;
|
return FS_RESULT_FATAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,171 +1,171 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// File description
|
// File description
|
||||||
// -------------
|
// -------------
|
||||||
/* Here we handle /dev/net and /dev/net/ncd/manage requests.
|
/* Here we handle /dev/net and /dev/net/ncd/manage requests.
|
||||||
|
|
||||||
|
|
||||||
// -----------------------
|
// -----------------------
|
||||||
The /dev/net/kd/request requests are part of what is called WiiConnect24,
|
The /dev/net/kd/request requests are part of what is called WiiConnect24,
|
||||||
it's used by for example SSBB, Mario Kart, Metroid Prime 3
|
it's used by for example SSBB, Mario Kart, Metroid Prime 3
|
||||||
|
|
||||||
0x01 SuspendScheduler (Input: none, Output: 32 bytes)
|
0x01 SuspendScheduler (Input: none, Output: 32 bytes)
|
||||||
0x02 ExecTrySuspendScheduler (Input: 32 bytes, Output: 32 bytes) // Sounds like it will
|
0x02 ExecTrySuspendScheduler (Input: 32 bytes, Output: 32 bytes) // Sounds like it will
|
||||||
check if it should suspend the updates scheduler or not. If I returned
|
check if it should suspend the updates scheduler or not. If I returned
|
||||||
(OutBuffer: 0, Ret: -1) to Metroid Prime 3 it got stuck in an endless loops of
|
(OutBuffer: 0, Ret: -1) to Metroid Prime 3 it got stuck in an endless loops of
|
||||||
requests, probably harmless but I changed it to (OutBuffer: 1, Ret: 0) to stop
|
requests, probably harmless but I changed it to (OutBuffer: 1, Ret: 0) to stop
|
||||||
the calls. However then it also calls 0x3 and then changes its error message
|
the calls. However then it also calls 0x3 and then changes its error message
|
||||||
to a Wii Memory error message from just a general Error message.
|
to a Wii Memory error message from just a general Error message.
|
||||||
|
|
||||||
0x03 ? (Input: none, Output: 32 bytes) // This is only called if 0x02
|
0x03 ? (Input: none, Output: 32 bytes) // This is only called if 0x02
|
||||||
does not return -1
|
does not return -1
|
||||||
0x0f NWC24iRequestGenerateUserId (Input: none, Output: 32 bytes)
|
0x0f NWC24iRequestGenerateUserId (Input: none, Output: 32 bytes)
|
||||||
|
|
||||||
Requests are made in this order by these games
|
Requests are made in this order by these games
|
||||||
Mario Kart: 2, 1, f, 3
|
Mario Kart: 2, 1, f, 3
|
||||||
SSBB: 2, 3
|
SSBB: 2, 3
|
||||||
|
|
||||||
For Mario Kart I had to return -1 from at least 2, f and 3 to convince it that the network
|
For Mario Kart I had to return -1 from at least 2, f and 3 to convince it that the network
|
||||||
was unavaliable and prevent if from looking for shared2/wc24 files (and do a PPCHalt when
|
was unavaliable and prevent if from looking for shared2/wc24 files (and do a PPCHalt when
|
||||||
it failed)
|
it failed)
|
||||||
// -------
|
// -------
|
||||||
|
|
||||||
*/
|
*/
|
||||||
// =============
|
// =============
|
||||||
|
|
||||||
|
|
||||||
#include "WII_IPC_HLE_Device_net.h"
|
#include "WII_IPC_HLE_Device_net.h"
|
||||||
|
|
||||||
|
|
||||||
// **********************************************************************************
|
// **********************************************************************************
|
||||||
// Handle /dev/net/kd/request requests
|
// Handle /dev/net/kd/request requests
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_net_kd_request::CWII_IPC_HLE_Device_net_kd_request(u32 _DeviceID, const std::string& _rDeviceName)
|
CWII_IPC_HLE_Device_net_kd_request::CWII_IPC_HLE_Device_net_kd_request(u32 _DeviceID, const std::string& _rDeviceName)
|
||||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_net_kd_request::~CWII_IPC_HLE_Device_net_kd_request()
|
CWII_IPC_HLE_Device_net_kd_request::~CWII_IPC_HLE_Device_net_kd_request()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_net_kd_request::Open(u32 _CommandAddress, u32 _Mode)
|
bool CWII_IPC_HLE_Device_net_kd_request::Open(u32 _CommandAddress, u32 _Mode)
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_NET, "NET_KD_REQ: Open");
|
LOG(WII_IPC_NET, "NET_KD_REQ: Open");
|
||||||
Memory::Write_U32(GetDeviceID(), _CommandAddress + 4);
|
Memory::Write_U32(GetDeviceID(), _CommandAddress + 4);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_net_kd_request::Close(u32 _CommandAddress)
|
bool CWII_IPC_HLE_Device_net_kd_request::Close(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_NET, "NET_KD_REQ: Close");
|
LOG(WII_IPC_NET, "NET_KD_REQ: Close");
|
||||||
Memory::Write_U32(0, _CommandAddress + 4);
|
Memory::Write_U32(0, _CommandAddress + 4);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_net_kd_request::IOCtl(u32 _CommandAddress)
|
bool CWII_IPC_HLE_Device_net_kd_request::IOCtl(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
|
u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
|
||||||
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
||||||
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
||||||
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||||
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
||||||
|
|
||||||
u32 ReturnValue = ExecuteCommand(Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
u32 ReturnValue = ExecuteCommand(Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
||||||
|
|
||||||
LOG(WII_IPC_NET, "NET_KD_REQ: IOCtl (Device=%s) (Parameter: 0x%02x)", GetDeviceName().c_str(), Parameter);
|
LOG(WII_IPC_NET, "NET_KD_REQ: IOCtl (Device=%s) (Parameter: 0x%02x)", GetDeviceName().c_str(), Parameter);
|
||||||
|
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress + 4);
|
Memory::Write_U32(ReturnValue, _CommandAddress + 4);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 CWII_IPC_HLE_Device_net_kd_request::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize)
|
s32 CWII_IPC_HLE_Device_net_kd_request::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize)
|
||||||
{
|
{
|
||||||
// Clean the location of the output buffer to zeroes as a safety precaution */
|
// Clean the location of the output buffer to zeroes as a safety precaution */
|
||||||
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
||||||
|
|
||||||
switch(_Parameter)
|
switch(_Parameter)
|
||||||
{
|
{
|
||||||
case 1: // SuspendScheduler (Input: none, Output: 32 bytes)
|
case 1: // SuspendScheduler (Input: none, Output: 32 bytes)
|
||||||
//Memory::Write_U32(0, _BufferOut);
|
//Memory::Write_U32(0, _BufferOut);
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
case 2: // ExecTrySuspendScheduler (Input: 32 bytes, Output: 32 bytes).
|
case 2: // ExecTrySuspendScheduler (Input: 32 bytes, Output: 32 bytes).
|
||||||
DumpCommands(_BufferIn, _BufferInSize / 4, LogTypes::WII_IPC_NET);
|
DumpCommands(_BufferIn, _BufferInSize / 4, LogTypes::WII_IPC_NET);
|
||||||
Memory::Write_U32(1, _BufferOut);
|
Memory::Write_U32(1, _BufferOut);
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case 3: // ? (Input: none, Output: 32 bytes)
|
case 3: // ? (Input: none, Output: 32 bytes)
|
||||||
//Memory::Write_U32(0, _BufferOut);
|
//Memory::Write_U32(0, _BufferOut);
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
case 0xf: // NWC24iRequestGenerateUserId (Input: none, Output: 32 bytes)
|
case 0xf: // NWC24iRequestGenerateUserId (Input: none, Output: 32 bytes)
|
||||||
//Memory::Write_U32(0, _BufferOut);
|
//Memory::Write_U32(0, _BufferOut);
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_dbg_assert_msg_(WII_IPC_NET, 0, "/dev/net/kd/request::IOCtl request 0x%x (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
|
_dbg_assert_msg_(WII_IPC_NET, 0, "/dev/net/kd/request::IOCtl request 0x%x (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
|
||||||
_Parameter, _BufferIn, _BufferInSize, _BufferOut, _BufferOutSize);
|
_Parameter, _BufferIn, _BufferInSize, _BufferOut, _BufferOutSize);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We return a success for any potential unknown requests
|
// We return a success for any potential unknown requests
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// **********************************************************************************
|
// **********************************************************************************
|
||||||
// Handle /dev/net/ncd/manage requests
|
// Handle /dev/net/ncd/manage requests
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_net_ncd_manage::CWII_IPC_HLE_Device_net_ncd_manage(u32 _DeviceID, const std::string& _rDeviceName)
|
CWII_IPC_HLE_Device_net_ncd_manage::CWII_IPC_HLE_Device_net_ncd_manage(u32 _DeviceID, const std::string& _rDeviceName)
|
||||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_net_ncd_manage::~CWII_IPC_HLE_Device_net_ncd_manage()
|
CWII_IPC_HLE_Device_net_ncd_manage::~CWII_IPC_HLE_Device_net_ncd_manage()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_net_ncd_manage::Open(u32 _CommandAddress, u32 _Mode)
|
bool CWII_IPC_HLE_Device_net_ncd_manage::Open(u32 _CommandAddress, u32 _Mode)
|
||||||
{
|
{
|
||||||
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
|
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_net_ncd_manage::IOCtlV(u32 _CommandAddress)
|
bool CWII_IPC_HLE_Device_net_ncd_manage::IOCtlV(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
u32 ReturnValue = 0;
|
u32 ReturnValue = 0;
|
||||||
|
|
||||||
SIOCtlVBuffer CommandBuffer(_CommandAddress);
|
SIOCtlVBuffer CommandBuffer(_CommandAddress);
|
||||||
|
|
||||||
switch(CommandBuffer.Parameter)
|
switch(CommandBuffer.Parameter)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
LOG(WII_IPC_NET, "NET_NCD_MANAGE IOCtlV: %i", CommandBuffer.Parameter);
|
LOG(WII_IPC_NET, "NET_NCD_MANAGE IOCtlV: %i", CommandBuffer.Parameter);
|
||||||
_dbg_assert_msg_(WII_IPC_NET, 0, "NET_NCD_MANAGE IOCtlV: %i", CommandBuffer.Parameter);
|
_dbg_assert_msg_(WII_IPC_NET, 0, "NET_NCD_MANAGE IOCtlV: %i", CommandBuffer.Parameter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress+4);
|
Memory::Write_U32(ReturnValue, _CommandAddress+4);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
|
@ -1,158 +1,158 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
#include "WII_IPC_HLE_Device_sdio_slot0.h"
|
#include "WII_IPC_HLE_Device_sdio_slot0.h"
|
||||||
|
|
||||||
#include "../HW/CPU.h"
|
#include "../HW/CPU.h"
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
#include "../Core.h"
|
#include "../Core.h"
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
//
|
//
|
||||||
CWII_IPC_HLE_Device_sdio_slot0::CWII_IPC_HLE_Device_sdio_slot0(u32 _DeviceID, const std::string& _rDeviceName )
|
CWII_IPC_HLE_Device_sdio_slot0::CWII_IPC_HLE_Device_sdio_slot0(u32 _DeviceID, const std::string& _rDeviceName )
|
||||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
//
|
//
|
||||||
CWII_IPC_HLE_Device_sdio_slot0::~CWII_IPC_HLE_Device_sdio_slot0()
|
CWII_IPC_HLE_Device_sdio_slot0::~CWII_IPC_HLE_Device_sdio_slot0()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
//
|
//
|
||||||
bool
|
bool
|
||||||
CWII_IPC_HLE_Device_sdio_slot0::Open(u32 _CommandAddress, u32 _Mode)
|
CWII_IPC_HLE_Device_sdio_slot0::Open(u32 _CommandAddress, u32 _Mode)
|
||||||
{
|
{
|
||||||
LOG(WII_IPC_SD, "SD: Open");
|
LOG(WII_IPC_SD, "SD: Open");
|
||||||
Memory::Write_U32(GetDeviceID(), _CommandAddress + 0x4);
|
Memory::Write_U32(GetDeviceID(), _CommandAddress + 0x4);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
// The front SD slot
|
// The front SD slot
|
||||||
bool CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress)
|
bool CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
//LOG(WII_IPC_FILEIO, "*************************************");
|
//LOG(WII_IPC_FILEIO, "*************************************");
|
||||||
//LOG(WII_IPC_FILEIO, "CWII_IPC_HLE_Device_sdio_slot0::IOCtl");
|
//LOG(WII_IPC_FILEIO, "CWII_IPC_HLE_Device_sdio_slot0::IOCtl");
|
||||||
//LOG(WII_IPC_FILEIO, "*************************************");
|
//LOG(WII_IPC_FILEIO, "*************************************");
|
||||||
|
|
||||||
// DumpCommands(_CommandAddress);
|
// DumpCommands(_CommandAddress);
|
||||||
|
|
||||||
u32 Cmd = Memory::Read_U32(_CommandAddress + 0xC);
|
u32 Cmd = Memory::Read_U32(_CommandAddress + 0xC);
|
||||||
// TODO: Use Cmd for something?
|
// TODO: Use Cmd for something?
|
||||||
|
|
||||||
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
||||||
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
||||||
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||||
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
||||||
|
|
||||||
//LOG(WII_IPC_SD, "%s Cmd 0x%x - BufferIn(0x%08x, 0x%x) BufferOut(0x%08x, 0x%x)",
|
//LOG(WII_IPC_SD, "%s Cmd 0x%x - BufferIn(0x%08x, 0x%x) BufferOut(0x%08x, 0x%x)",
|
||||||
// GetDeviceName().c_str(), Cmd, BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
// GetDeviceName().c_str(), Cmd, BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
||||||
|
|
||||||
/* As a safety precaution we fill the out buffer with zeroes to avoid
|
/* As a safety precaution we fill the out buffer with zeroes to avoid
|
||||||
returning nonsense values */
|
returning nonsense values */
|
||||||
Memory::Memset(BufferOut, 0, BufferOutSize);
|
Memory::Memset(BufferOut, 0, BufferOutSize);
|
||||||
|
|
||||||
u32 ReturnValue = 0;
|
u32 ReturnValue = 0;
|
||||||
switch (Cmd) {
|
switch (Cmd) {
|
||||||
case 1: // set_hc_reg
|
case 1: // set_hc_reg
|
||||||
LOGV(WII_IPC_SD, 0, "SD: set_hc_reg");
|
LOGV(WII_IPC_SD, 0, "SD: set_hc_reg");
|
||||||
break;
|
break;
|
||||||
case 2: // get_hc_reg
|
case 2: // get_hc_reg
|
||||||
LOGV(WII_IPC_SD, 0, "SD: get_hc_reg");
|
LOGV(WII_IPC_SD, 0, "SD: get_hc_reg");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: // reset, do nothing ?
|
case 4: // reset, do nothing ?
|
||||||
LOGV(WII_IPC_SD, 0, "SD: reset");
|
LOGV(WII_IPC_SD, 0, "SD: reset");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6: // sd_clock
|
case 6: // sd_clock
|
||||||
LOGV(WII_IPC_SD, 0, "SD: sd_clock");
|
LOGV(WII_IPC_SD, 0, "SD: sd_clock");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7: // Send cmd (Input: 24 bytes, Output: 10 bytes)
|
case 7: // Send cmd (Input: 24 bytes, Output: 10 bytes)
|
||||||
LOGV(WII_IPC_SD, 0, "SD: sendcmd");
|
LOGV(WII_IPC_SD, 0, "SD: sendcmd");
|
||||||
ReturnValue = ExecuteCommand(BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
ReturnValue = ExecuteCommand(BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 11: // sd_get_status
|
case 11: // sd_get_status
|
||||||
LOGV(WII_IPC_SD, 0, "SD: sd_get_status. Answer: SD card is not inserted", BufferOut);
|
LOGV(WII_IPC_SD, 0, "SD: sd_get_status. Answer: SD card is not inserted", BufferOut);
|
||||||
Memory::Write_U32(2, BufferOut); // SD card is not inserted
|
Memory::Write_U32(2, BufferOut); // SD card is not inserted
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PanicAlert("Unknown SD command (0x%08x)", Cmd);
|
PanicAlert("Unknown SD command (0x%08x)", Cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//DumpCommands(_CommandAddress);
|
//DumpCommands(_CommandAddress);
|
||||||
|
|
||||||
//LOG(WII_IPC_SD, "InBuffer");
|
//LOG(WII_IPC_SD, "InBuffer");
|
||||||
//DumpCommands(BufferIn, BufferInSize / 4, LogTypes::WII_IPC_SD);
|
//DumpCommands(BufferIn, BufferInSize / 4, LogTypes::WII_IPC_SD);
|
||||||
|
|
||||||
//LOG(WII_IPC_SD, "OutBuffer");
|
//LOG(WII_IPC_SD, "OutBuffer");
|
||||||
//DumpCommands(BufferOut, BufferOutSize);
|
//DumpCommands(BufferOut, BufferOutSize);
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
//
|
//
|
||||||
bool CWII_IPC_HLE_Device_sdio_slot0::IOCtlV(u32 _CommandAddress)
|
bool CWII_IPC_HLE_Device_sdio_slot0::IOCtlV(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
PanicAlert("CWII_IPC_HLE_Device_sdio_slot0::IOCtlV() unknown");
|
PanicAlert("CWII_IPC_HLE_Device_sdio_slot0::IOCtlV() unknown");
|
||||||
// SD_Read uses this
|
// SD_Read uses this
|
||||||
|
|
||||||
DumpCommands(_CommandAddress);
|
DumpCommands(_CommandAddress);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
//
|
//
|
||||||
u32 CWII_IPC_HLE_Device_sdio_slot0::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize)
|
u32 CWII_IPC_HLE_Device_sdio_slot0::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize)
|
||||||
{
|
{
|
||||||
/* The game will send us a SendCMD with this information. To be able to read and write
|
/* The game will send us a SendCMD with this information. To be able to read and write
|
||||||
to a file we need to prepare a 10 byte output buffer as response. */
|
to a file we need to prepare a 10 byte output buffer as response. */
|
||||||
struct Request {
|
struct Request {
|
||||||
u32 command;
|
u32 command;
|
||||||
u32 type;
|
u32 type;
|
||||||
u32 resp;
|
u32 resp;
|
||||||
u32 arg;
|
u32 arg;
|
||||||
u32 blocks;
|
u32 blocks;
|
||||||
u32 bsize;
|
u32 bsize;
|
||||||
u32 addr;
|
u32 addr;
|
||||||
} req;
|
} req;
|
||||||
req.command = Memory::Read_U32(_BufferIn + 0);
|
req.command = Memory::Read_U32(_BufferIn + 0);
|
||||||
req.type = Memory::Read_U32(_BufferIn + 4);
|
req.type = Memory::Read_U32(_BufferIn + 4);
|
||||||
req.resp = Memory::Read_U32(_BufferIn + 8);
|
req.resp = Memory::Read_U32(_BufferIn + 8);
|
||||||
req.arg = Memory::Read_U32(_BufferIn + 12);
|
req.arg = Memory::Read_U32(_BufferIn + 12);
|
||||||
req.blocks = Memory::Read_U32(_BufferIn + 16);
|
req.blocks = Memory::Read_U32(_BufferIn + 16);
|
||||||
req.bsize = Memory::Read_U32(_BufferIn + 20);
|
req.bsize = Memory::Read_U32(_BufferIn + 20);
|
||||||
req.addr = Memory::Read_U32(_BufferIn + 24);
|
req.addr = Memory::Read_U32(_BufferIn + 24);
|
||||||
//switch (req.command)
|
//switch (req.command)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,272 +1,272 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "WiiMote_HID_Attr.h"
|
#include "WiiMote_HID_Attr.h"
|
||||||
|
|
||||||
CAttribTable m_AttribTable;
|
CAttribTable m_AttribTable;
|
||||||
|
|
||||||
|
|
||||||
// 0x00 (checked)
|
// 0x00 (checked)
|
||||||
u8 ServiceRecordHandle[] = { 0x0a, 0x00, 0x01, 0x00, 0x00 };
|
u8 ServiceRecordHandle[] = { 0x0a, 0x00, 0x01, 0x00, 0x00 };
|
||||||
// 0x01 (checked)
|
// 0x01 (checked)
|
||||||
u8 SrvClassIDList[] = { 0x35, 0x03,
|
u8 SrvClassIDList[] = { 0x35, 0x03,
|
||||||
0x19, 0x11, 0x24 };
|
0x19, 0x11, 0x24 };
|
||||||
// 0x04 (checked)
|
// 0x04 (checked)
|
||||||
u8 ProtocolDescriptorList[] = { 0x35, 0x0D,
|
u8 ProtocolDescriptorList[] = { 0x35, 0x0D,
|
||||||
0x35, 0x06,
|
0x35, 0x06,
|
||||||
0x19, 0x01, 0x00, // Element 0
|
0x19, 0x01, 0x00, // Element 0
|
||||||
0x09, 0x00, 0x11, // Element 1
|
0x09, 0x00, 0x11, // Element 1
|
||||||
0x35, 0x03,
|
0x35, 0x03,
|
||||||
0x19, 0x00, 0x11}; // Element 0
|
0x19, 0x00, 0x11}; // Element 0
|
||||||
// 0x5 (checked)
|
// 0x5 (checked)
|
||||||
u8 BrowseGroupList[] = { 0x35, 0x03,
|
u8 BrowseGroupList[] = { 0x35, 0x03,
|
||||||
0x19, 0x10, 0x02 };
|
0x19, 0x10, 0x02 };
|
||||||
// 0x6 (checked)
|
// 0x6 (checked)
|
||||||
u8 LanguageBaseAttributeIDList[] = { 0x35, 0x09,
|
u8 LanguageBaseAttributeIDList[] = { 0x35, 0x09,
|
||||||
0x09, 0x65, 0x6e,
|
0x09, 0x65, 0x6e,
|
||||||
0x09, 0x00, 0x6a,
|
0x09, 0x00, 0x6a,
|
||||||
0x09, 0x01, 0x00 };
|
0x09, 0x01, 0x00 };
|
||||||
// 0x09 (checked)
|
// 0x09 (checked)
|
||||||
u8 BluetoothProfileDescriptorList[] = { 0x35, 0x08,
|
u8 BluetoothProfileDescriptorList[] = { 0x35, 0x08,
|
||||||
0x35, 0x06,
|
0x35, 0x06,
|
||||||
0x19, 0x11, 0x24,
|
0x19, 0x11, 0x24,
|
||||||
0x09, 0x01, 0x00 };
|
0x09, 0x01, 0x00 };
|
||||||
// 0x0D (checked)
|
// 0x0D (checked)
|
||||||
u8 AdditionalProtocolDescriptorLists[] = { 0x35, 0x0F,
|
u8 AdditionalProtocolDescriptorLists[] = { 0x35, 0x0F,
|
||||||
0x35, 0x0D,
|
0x35, 0x0D,
|
||||||
0x35, 0x06,
|
0x35, 0x06,
|
||||||
0x19, 0x01, 0x00,
|
0x19, 0x01, 0x00,
|
||||||
0x09, 0x00, 0x13,
|
0x09, 0x00, 0x13,
|
||||||
0x35, 0x03,
|
0x35, 0x03,
|
||||||
0x19, 0x00, 0x11 };
|
0x19, 0x00, 0x11 };
|
||||||
// 0x100
|
// 0x100
|
||||||
u8 ServiceName[] = { 0x25, 0x13, 'N','i','n','t','e','n','d','o',' ','R','V','L','-','C','N','T','-','0','1' };
|
u8 ServiceName[] = { 0x25, 0x13, 'N','i','n','t','e','n','d','o',' ','R','V','L','-','C','N','T','-','0','1' };
|
||||||
// 0x101
|
// 0x101
|
||||||
u8 ServiceDescription[] = { 0x25, 0x13, 'N','i','n','t','e','n','d','o',' ','R','V','L','-','C','N','T','-','0','1' };
|
u8 ServiceDescription[] = { 0x25, 0x13, 'N','i','n','t','e','n','d','o',' ','R','V','L','-','C','N','T','-','0','1' };
|
||||||
// 0x102
|
// 0x102
|
||||||
u8 ProviderName [] = { 0x25, 0x8, 'N','i','n','t','e','n','d','o'};
|
u8 ProviderName [] = { 0x25, 0x8, 'N','i','n','t','e','n','d','o'};
|
||||||
|
|
||||||
// 0x200
|
// 0x200
|
||||||
u8 HIDDeviceReleaseNumber[] = { 0x09, 0x01, 0x00 };
|
u8 HIDDeviceReleaseNumber[] = { 0x09, 0x01, 0x00 };
|
||||||
// 0x201
|
// 0x201
|
||||||
u8 HIDParserVersion[] = { 0x09, 0x01, 0x11 };
|
u8 HIDParserVersion[] = { 0x09, 0x01, 0x11 };
|
||||||
// 0x202
|
// 0x202
|
||||||
u8 HIDDeviceSubclass[] = { 0x09, 0x00, 0x04 };
|
u8 HIDDeviceSubclass[] = { 0x09, 0x00, 0x04 };
|
||||||
// 0x203
|
// 0x203
|
||||||
u8 HIDCountryCode[] = { 0x09, 0x00, 0x33 };
|
u8 HIDCountryCode[] = { 0x09, 0x00, 0x33 };
|
||||||
// 0x204
|
// 0x204
|
||||||
u8 HIDVirtualCable[] = { 0x09, 0x00, 0x00 };
|
u8 HIDVirtualCable[] = { 0x09, 0x00, 0x00 };
|
||||||
// 0x205
|
// 0x205
|
||||||
u8 HIDReconnectInitiate[] = { 0x09, 0x00, 0x01 };
|
u8 HIDReconnectInitiate[] = { 0x09, 0x00, 0x01 };
|
||||||
|
|
||||||
// 0x206
|
// 0x206
|
||||||
u8 HIDDescriptorList[] = { 0x35, 0xDF,
|
u8 HIDDescriptorList[] = { 0x35, 0xDF,
|
||||||
0x35, 0xDD,
|
0x35, 0xDD,
|
||||||
0x08, 0x22, // Element 0
|
0x08, 0x22, // Element 0
|
||||||
0x25, 0xD9, // hmm... <- 0x25 is a string but there is Data
|
0x25, 0xD9, // hmm... <- 0x25 is a string but there is Data
|
||||||
|
|
||||||
// 0xD9 Bytes - Element 1
|
// 0xD9 Bytes - Element 1
|
||||||
0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10,
|
0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10,
|
||||||
0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
|
0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
|
||||||
0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00,
|
0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00,
|
||||||
0x85, 0x11, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
0x85, 0x11, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00,
|
0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00,
|
||||||
0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
0x85, 0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
0x85, 0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
0x85, 0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
|
0x85, 0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
|
||||||
0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00,
|
0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00,
|
||||||
0x85, 0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
|
0x85, 0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
|
||||||
0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
0x85, 0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
0x85, 0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
0xc0 }; // end tag
|
0xc0 }; // end tag
|
||||||
|
|
||||||
|
|
||||||
// 0x207
|
// 0x207
|
||||||
u8 HIDLANGIDBaseList[] = { 0x35, 0x08,
|
u8 HIDLANGIDBaseList[] = { 0x35, 0x08,
|
||||||
0x35, 0x06,
|
0x35, 0x06,
|
||||||
0x09, 0x04, 0x09,
|
0x09, 0x04, 0x09,
|
||||||
0x09, 0x01, 0x00 };
|
0x09, 0x01, 0x00 };
|
||||||
|
|
||||||
// 0x208
|
// 0x208
|
||||||
u8 HIDSDPDisable[] = { 0x28, 0x00 };
|
u8 HIDSDPDisable[] = { 0x28, 0x00 };
|
||||||
// 0x209
|
// 0x209
|
||||||
u8 HIDBatteryPower[] = { 0x28, 0x01 };
|
u8 HIDBatteryPower[] = { 0x28, 0x01 };
|
||||||
// 0x20a
|
// 0x20a
|
||||||
u8 HIDRemoteWake[] = { 0x28, 0x01 };
|
u8 HIDRemoteWake[] = { 0x28, 0x01 };
|
||||||
// 0x20b
|
// 0x20b
|
||||||
u8 HIDUnk_020B[] = { 0x09, 0x01, 0x00 };
|
u8 HIDUnk_020B[] = { 0x09, 0x01, 0x00 };
|
||||||
// 0x20c
|
// 0x20c
|
||||||
u8 HIDUnk_020C[] = { 0x09, 0x0c, 0x80 };
|
u8 HIDUnk_020C[] = { 0x09, 0x0c, 0x80 };
|
||||||
// 0x20d
|
// 0x20d
|
||||||
u8 HIDUnk_020D[] = { 0x28, 0x00 };
|
u8 HIDUnk_020D[] = { 0x28, 0x00 };
|
||||||
// 0x20e
|
// 0x20e
|
||||||
u8 HIDBootDevice[] = { 0x28, 0x00 };
|
u8 HIDBootDevice[] = { 0x28, 0x00 };
|
||||||
|
|
||||||
|
|
||||||
u8 packet1[] = {
|
u8 packet1[] = {
|
||||||
0x00, 0x7b, 0x00, 0x76, 0x36, 0x01, 0xcc, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x01,
|
0x00, 0x7b, 0x00, 0x76, 0x36, 0x01, 0xcc, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x01,
|
||||||
0x00, 0x00, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x24, 0x09, 0x00, 0x04, 0x35, 0x0d, 0x35,
|
0x00, 0x00, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x24, 0x09, 0x00, 0x04, 0x35, 0x0d, 0x35,
|
||||||
0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x11, 0x35, 0x03, 0x19, 0x00, 0x11, 0x09, 0x00, 0x05, 0x35,
|
0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x11, 0x35, 0x03, 0x19, 0x00, 0x11, 0x09, 0x00, 0x05, 0x35,
|
||||||
0x03, 0x19, 0x10, 0x02, 0x09, 0x00, 0x06, 0x35, 0x09, 0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09,
|
0x03, 0x19, 0x10, 0x02, 0x09, 0x00, 0x06, 0x35, 0x09, 0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09,
|
||||||
0x01, 0x00, 0x09, 0x00, 0x09, 0x35, 0x08, 0x35, 0x06, 0x19, 0x11, 0x24, 0x09, 0x01, 0x00, 0x09,
|
0x01, 0x00, 0x09, 0x00, 0x09, 0x35, 0x08, 0x35, 0x06, 0x19, 0x11, 0x24, 0x09, 0x01, 0x00, 0x09,
|
||||||
0x00, 0x0d, 0x35, 0x0f, 0x35, 0x0d, 0x35, 0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x13, 0x35, 0x03,
|
0x00, 0x0d, 0x35, 0x0f, 0x35, 0x0d, 0x35, 0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x13, 0x35, 0x03,
|
||||||
0x19, 0x00, 0x11, 0x09, 0x01, 0x00, 0x25, 0x13, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f,
|
0x19, 0x00, 0x11, 0x09, 0x01, 0x00, 0x25, 0x13, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f,
|
||||||
0x20, 0x52, 0x56, 0x4c, 0x2d, 0x43, 0x4e, 0x54, 0x2d, 0x30, 0x31, 0x09, 0x01, 0x02, 0x00, 0x76,
|
0x20, 0x52, 0x56, 0x4c, 0x2d, 0x43, 0x4e, 0x54, 0x2d, 0x30, 0x31, 0x09, 0x01, 0x02, 0x00, 0x76,
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 packet2[] = {
|
u8 packet2[] = {
|
||||||
0x00, 0x7b, 0x00, 0x76, 0x01, 0x25, 0x13, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e,
|
0x00, 0x7b, 0x00, 0x76, 0x01, 0x25, 0x13, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e,
|
||||||
0x64, 0x6f, 0x20, 0x52, 0x56, 0x4c, 0x2d, 0x43, 0x4e, 0x54, 0x2d, 0x30, 0x31, 0x09, 0x01, 0x02,
|
0x64, 0x6f, 0x20, 0x52, 0x56, 0x4c, 0x2d, 0x43, 0x4e, 0x54, 0x2d, 0x30, 0x31, 0x09, 0x01, 0x02,
|
||||||
0x25, 0x08, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, 0x09, 0x02, 0x00, 0x09, 0x01, 0x00,
|
0x25, 0x08, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, 0x09, 0x02, 0x00, 0x09, 0x01, 0x00,
|
||||||
0x09, 0x02, 0x01, 0x09, 0x01, 0x11, 0x09, 0x02, 0x02, 0x08, 0x04, 0x09, 0x02, 0x03, 0x08, 0x33,
|
0x09, 0x02, 0x01, 0x09, 0x01, 0x11, 0x09, 0x02, 0x02, 0x08, 0x04, 0x09, 0x02, 0x03, 0x08, 0x33,
|
||||||
0x09, 0x02, 0x04, 0x28, 0x00, 0x09, 0x02, 0x05, 0x28, 0x01, 0x09, 0x02, 0x06, 0x35, 0xdf, 0x35,
|
0x09, 0x02, 0x04, 0x28, 0x00, 0x09, 0x02, 0x05, 0x28, 0x01, 0x09, 0x02, 0x06, 0x35, 0xdf, 0x35,
|
||||||
0xdd, 0x08, 0x22, 0x25, 0xd9, 0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10, 0x15, 0x00, 0x26,
|
0xdd, 0x08, 0x22, 0x25, 0xd9, 0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10, 0x15, 0x00, 0x26,
|
||||||
0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00, 0x85, 0x11, 0x95,
|
0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00, 0x85, 0x11, 0x95,
|
||||||
0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00, 0x02, 0x00, 0xec,
|
0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00, 0x02, 0x00, 0xec,
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 packet3[] = {
|
u8 packet3[] = {
|
||||||
|
|
||||||
0x00, 0x7b, 0x00, 0x76, 0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85,
|
0x00, 0x7b, 0x00, 0x76, 0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85,
|
||||||
0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85,
|
0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85,
|
||||||
0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00, 0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00, 0x85,
|
0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00, 0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00, 0x85,
|
||||||
0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00, 0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85,
|
0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00, 0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85,
|
||||||
0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00, 0x85,
|
0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00, 0x85,
|
||||||
0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00, 0x85,
|
0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00, 0x85,
|
||||||
0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00, 0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00, 0x85,
|
0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00, 0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00, 0x85,
|
||||||
0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00, 0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x02, 0x01, 0x62,
|
0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00, 0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x02, 0x01, 0x62,
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 packet4[] = {
|
u8 packet4[] = {
|
||||||
0x00, 0x70, 0x00, 0x6d, 0x81, 0x00, 0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81,
|
0x00, 0x70, 0x00, 0x6d, 0x81, 0x00, 0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81,
|
||||||
0x00, 0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81,
|
0x00, 0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81,
|
||||||
0x00, 0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81,
|
0x00, 0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81,
|
||||||
0x00, 0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81,
|
0x00, 0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81,
|
||||||
0x00, 0xc0, 0x09, 0x02, 0x07, 0x35, 0x08, 0x35, 0x06, 0x09, 0x04, 0x09, 0x09, 0x01, 0x00, 0x09,
|
0x00, 0xc0, 0x09, 0x02, 0x07, 0x35, 0x08, 0x35, 0x06, 0x09, 0x04, 0x09, 0x09, 0x01, 0x00, 0x09,
|
||||||
0x02, 0x08, 0x28, 0x00, 0x09, 0x02, 0x09, 0x28, 0x01, 0x09, 0x02, 0x0a, 0x28, 0x01, 0x09, 0x02,
|
0x02, 0x08, 0x28, 0x00, 0x09, 0x02, 0x09, 0x28, 0x01, 0x09, 0x02, 0x0a, 0x28, 0x01, 0x09, 0x02,
|
||||||
0x0b, 0x09, 0x01, 0x00, 0x09, 0x02, 0x0c, 0x09, 0x0c, 0x80, 0x09, 0x02, 0x0d, 0x28, 0x00, 0x09,
|
0x0b, 0x09, 0x01, 0x00, 0x09, 0x02, 0x0c, 0x09, 0x0c, 0x80, 0x09, 0x02, 0x0d, 0x28, 0x00, 0x09,
|
||||||
0x02, 0x0e, 0x28, 0x00, 0x00,
|
0x02, 0x0e, 0x28, 0x00, 0x00,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
u8 packet4_0x10001[] = {
|
u8 packet4_0x10001[] = {
|
||||||
0x00, 0x60, 0x00, 0x5d, 0x36, 0x00, 0x5a, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x01,
|
0x00, 0x60, 0x00, 0x5d, 0x36, 0x00, 0x5a, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x01,
|
||||||
0x00, 0x01, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x12, 0x00, 0x09, 0x00, 0x04, 0x35, 0x0d, 0x35,
|
0x00, 0x01, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x12, 0x00, 0x09, 0x00, 0x04, 0x35, 0x0d, 0x35,
|
||||||
0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x00, 0x01, 0x09, 0x00, 0x05, 0x35,
|
0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x00, 0x01, 0x09, 0x00, 0x05, 0x35,
|
||||||
0x03, 0x19, 0x10, 0x02, 0x09, 0x00, 0x09, 0x35, 0x08, 0x35, 0x06, 0x19, 0x12, 0x00, 0x09, 0x01,
|
0x03, 0x19, 0x10, 0x02, 0x09, 0x00, 0x09, 0x35, 0x08, 0x35, 0x06, 0x19, 0x12, 0x00, 0x09, 0x01,
|
||||||
0x00, 0x09, 0x02, 0x00, 0x09, 0x01, 0x00, 0x09, 0x02, 0x01, 0x09, 0x05, 0x7e, 0x09, 0x02, 0x02,
|
0x00, 0x09, 0x02, 0x00, 0x09, 0x01, 0x00, 0x09, 0x02, 0x01, 0x09, 0x05, 0x7e, 0x09, 0x02, 0x02,
|
||||||
0x09, 0x03, 0x06, 0x09, 0x02, 0x03, 0x09, 0x06, 0x00, 0x09, 0x02, 0x04, 0x28, 0x01, 0x09, 0x02,
|
0x09, 0x03, 0x06, 0x09, 0x02, 0x03, 0x09, 0x06, 0x00, 0x09, 0x02, 0x04, 0x28, 0x01, 0x09, 0x02,
|
||||||
0x05, 0x09, 0x00, 0x02, 0x00,
|
0x05, 0x09, 0x00, 0x02, 0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const u8* GetAttribPacket(u32 serviceHandle, u32 cont, u32& _size)
|
const u8* GetAttribPacket(u32 serviceHandle, u32 cont, u32& _size)
|
||||||
{
|
{
|
||||||
if (serviceHandle == 0x10000)
|
if (serviceHandle == 0x10000)
|
||||||
{
|
{
|
||||||
if (cont == 0)
|
if (cont == 0)
|
||||||
{
|
{
|
||||||
_size = sizeof(packet1);
|
_size = sizeof(packet1);
|
||||||
return packet1;
|
return packet1;
|
||||||
}
|
}
|
||||||
else if (cont == 0x76)
|
else if (cont == 0x76)
|
||||||
{
|
{
|
||||||
_size = sizeof(packet2);
|
_size = sizeof(packet2);
|
||||||
return packet2;
|
return packet2;
|
||||||
}
|
}
|
||||||
else if (cont == 0xec)
|
else if (cont == 0xec)
|
||||||
{
|
{
|
||||||
_size = sizeof(packet3);
|
_size = sizeof(packet3);
|
||||||
return packet3;
|
return packet3;
|
||||||
}
|
}
|
||||||
else if (cont == 0x162)
|
else if (cont == 0x162)
|
||||||
{
|
{
|
||||||
_size = sizeof(packet4);
|
_size = sizeof(packet4);
|
||||||
return packet4;
|
return packet4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serviceHandle == 0x10001)
|
if (serviceHandle == 0x10001)
|
||||||
{
|
{
|
||||||
_dbg_assert_(WII_IPC_WIIMOTE, cont == 0x00);
|
_dbg_assert_(WII_IPC_WIIMOTE, cont == 0x00);
|
||||||
_size = sizeof(packet4_0x10001);
|
_size = sizeof(packet4_0x10001);
|
||||||
return packet4_0x10001;
|
return packet4_0x10001;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitAttribTable()
|
void InitAttribTable()
|
||||||
{
|
{
|
||||||
m_AttribTable.push_back(SAttrib(0x00, ServiceRecordHandle, sizeof(ServiceRecordHandle)));
|
m_AttribTable.push_back(SAttrib(0x00, ServiceRecordHandle, sizeof(ServiceRecordHandle)));
|
||||||
m_AttribTable.push_back(SAttrib(0x01, SrvClassIDList, sizeof(SrvClassIDList)));
|
m_AttribTable.push_back(SAttrib(0x01, SrvClassIDList, sizeof(SrvClassIDList)));
|
||||||
m_AttribTable.push_back(SAttrib(0x04, ProtocolDescriptorList, sizeof(ProtocolDescriptorList)));
|
m_AttribTable.push_back(SAttrib(0x04, ProtocolDescriptorList, sizeof(ProtocolDescriptorList)));
|
||||||
m_AttribTable.push_back(SAttrib(0x05, BrowseGroupList, sizeof(BrowseGroupList)));
|
m_AttribTable.push_back(SAttrib(0x05, BrowseGroupList, sizeof(BrowseGroupList)));
|
||||||
m_AttribTable.push_back(SAttrib(0x06, LanguageBaseAttributeIDList, sizeof(LanguageBaseAttributeIDList)));
|
m_AttribTable.push_back(SAttrib(0x06, LanguageBaseAttributeIDList, sizeof(LanguageBaseAttributeIDList)));
|
||||||
m_AttribTable.push_back(SAttrib(0x09, BluetoothProfileDescriptorList, sizeof(BluetoothProfileDescriptorList)));
|
m_AttribTable.push_back(SAttrib(0x09, BluetoothProfileDescriptorList, sizeof(BluetoothProfileDescriptorList)));
|
||||||
m_AttribTable.push_back(SAttrib(0x0D, AdditionalProtocolDescriptorLists, sizeof(AdditionalProtocolDescriptorLists)));
|
m_AttribTable.push_back(SAttrib(0x0D, AdditionalProtocolDescriptorLists, sizeof(AdditionalProtocolDescriptorLists)));
|
||||||
|
|
||||||
|
|
||||||
m_AttribTable.push_back(SAttrib(0x100, ServiceName, sizeof(ServiceName)));
|
m_AttribTable.push_back(SAttrib(0x100, ServiceName, sizeof(ServiceName)));
|
||||||
m_AttribTable.push_back(SAttrib(0x101, ServiceDescription, sizeof(ServiceDescription)));
|
m_AttribTable.push_back(SAttrib(0x101, ServiceDescription, sizeof(ServiceDescription)));
|
||||||
m_AttribTable.push_back(SAttrib(0x102, ProviderName, sizeof(ProviderName)));
|
m_AttribTable.push_back(SAttrib(0x102, ProviderName, sizeof(ProviderName)));
|
||||||
|
|
||||||
m_AttribTable.push_back(SAttrib(0x200, HIDDeviceReleaseNumber, sizeof(HIDDeviceReleaseNumber)));
|
m_AttribTable.push_back(SAttrib(0x200, HIDDeviceReleaseNumber, sizeof(HIDDeviceReleaseNumber)));
|
||||||
m_AttribTable.push_back(SAttrib(0x201, HIDParserVersion, sizeof(HIDParserVersion)));
|
m_AttribTable.push_back(SAttrib(0x201, HIDParserVersion, sizeof(HIDParserVersion)));
|
||||||
m_AttribTable.push_back(SAttrib(0x202, HIDDeviceSubclass, sizeof(HIDDeviceSubclass)));
|
m_AttribTable.push_back(SAttrib(0x202, HIDDeviceSubclass, sizeof(HIDDeviceSubclass)));
|
||||||
m_AttribTable.push_back(SAttrib(0x203, HIDCountryCode, sizeof(HIDCountryCode)));
|
m_AttribTable.push_back(SAttrib(0x203, HIDCountryCode, sizeof(HIDCountryCode)));
|
||||||
m_AttribTable.push_back(SAttrib(0x204, HIDVirtualCable, sizeof(HIDVirtualCable)));
|
m_AttribTable.push_back(SAttrib(0x204, HIDVirtualCable, sizeof(HIDVirtualCable)));
|
||||||
m_AttribTable.push_back(SAttrib(0x205, HIDReconnectInitiate, sizeof(HIDReconnectInitiate)));
|
m_AttribTable.push_back(SAttrib(0x205, HIDReconnectInitiate, sizeof(HIDReconnectInitiate)));
|
||||||
m_AttribTable.push_back(SAttrib(0x206, HIDDescriptorList, sizeof(HIDDescriptorList)));
|
m_AttribTable.push_back(SAttrib(0x206, HIDDescriptorList, sizeof(HIDDescriptorList)));
|
||||||
m_AttribTable.push_back(SAttrib(0x207, HIDLANGIDBaseList, sizeof(HIDLANGIDBaseList)));
|
m_AttribTable.push_back(SAttrib(0x207, HIDLANGIDBaseList, sizeof(HIDLANGIDBaseList)));
|
||||||
m_AttribTable.push_back(SAttrib(0x208, HIDSDPDisable, sizeof(HIDSDPDisable)));
|
m_AttribTable.push_back(SAttrib(0x208, HIDSDPDisable, sizeof(HIDSDPDisable)));
|
||||||
m_AttribTable.push_back(SAttrib(0x209, HIDBatteryPower, sizeof(HIDBatteryPower)));
|
m_AttribTable.push_back(SAttrib(0x209, HIDBatteryPower, sizeof(HIDBatteryPower)));
|
||||||
m_AttribTable.push_back(SAttrib(0x20a, HIDRemoteWake, sizeof(HIDRemoteWake)));
|
m_AttribTable.push_back(SAttrib(0x20a, HIDRemoteWake, sizeof(HIDRemoteWake)));
|
||||||
m_AttribTable.push_back(SAttrib(0x20b, HIDUnk_020B, sizeof(HIDUnk_020B)));
|
m_AttribTable.push_back(SAttrib(0x20b, HIDUnk_020B, sizeof(HIDUnk_020B)));
|
||||||
m_AttribTable.push_back(SAttrib(0x20c, HIDUnk_020C, sizeof(HIDUnk_020C)));
|
m_AttribTable.push_back(SAttrib(0x20c, HIDUnk_020C, sizeof(HIDUnk_020C)));
|
||||||
m_AttribTable.push_back(SAttrib(0x20d, HIDUnk_020D, sizeof(HIDUnk_020D)));
|
m_AttribTable.push_back(SAttrib(0x20d, HIDUnk_020D, sizeof(HIDUnk_020D)));
|
||||||
m_AttribTable.push_back(SAttrib(0x20e, HIDBootDevice, sizeof(HIDBootDevice)));
|
m_AttribTable.push_back(SAttrib(0x20e, HIDBootDevice, sizeof(HIDBootDevice)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const CAttribTable& GetAttribTable()
|
const CAttribTable& GetAttribTable()
|
||||||
{
|
{
|
||||||
if (m_AttribTable.empty())
|
if (m_AttribTable.empty())
|
||||||
{
|
{
|
||||||
InitAttribTable();
|
InitAttribTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_AttribTable;
|
return m_AttribTable;
|
||||||
}
|
}
|
|
@ -1,368 +1,368 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#if defined(HAVE_WX) && HAVE_WX
|
#if defined(HAVE_WX) && HAVE_WX
|
||||||
#include <wx/datetime.h> // for the timestamps
|
#include <wx/datetime.h> // for the timestamps
|
||||||
#endif
|
#endif
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "LogManager.h"
|
#include "LogManager.h"
|
||||||
#include "PowerPC/PowerPC.h"
|
#include "PowerPC/PowerPC.h"
|
||||||
#include "PowerPC/SymbolDB.h" // for g_symbolDB
|
#include "PowerPC/SymbolDB.h" // for g_symbolDB
|
||||||
#include "Debugger/Debugger_SymbolMap.h"
|
#include "Debugger/Debugger_SymbolMap.h"
|
||||||
|
|
||||||
|
|
||||||
LogManager::SMessage (*LogManager::m_Messages)[MAX_MESSAGES];
|
LogManager::SMessage (*LogManager::m_Messages)[MAX_MESSAGES];
|
||||||
int LogManager::m_nextMessages[LogManager::VERBOSITY_LEVELS + 1];
|
int LogManager::m_nextMessages[LogManager::VERBOSITY_LEVELS + 1];
|
||||||
|
|
||||||
CDebugger_Log* LogManager::m_Log[LogTypes::NUMBER_OF_LOGS + (LogManager::VERBOSITY_LEVELS * 100)];
|
CDebugger_Log* LogManager::m_Log[LogTypes::NUMBER_OF_LOGS + (LogManager::VERBOSITY_LEVELS * 100)];
|
||||||
int LogManager::m_activeLog = LogTypes::MASTER_LOG;
|
int LogManager::m_activeLog = LogTypes::MASTER_LOG;
|
||||||
bool LogManager::m_bDirty = true;
|
bool LogManager::m_bDirty = true;
|
||||||
bool LogManager::m_bInitialized = false;
|
bool LogManager::m_bInitialized = false;
|
||||||
|
|
||||||
|
|
||||||
void __Log(int log, const char *format, ...)
|
void __Log(int log, const char *format, ...)
|
||||||
{
|
{
|
||||||
char* temp = (char*)alloca(strlen(format)+512);
|
char* temp = (char*)alloca(strlen(format)+512);
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
CharArrayFromFormatV(temp, 512, format, args);
|
CharArrayFromFormatV(temp, 512, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
LogManager::Log((LogTypes::LOG_TYPE)log, temp);
|
LogManager::Log((LogTypes::LOG_TYPE)log, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __Logv(int log, int v, const char *format, ...)
|
void __Logv(int log, int v, const char *format, ...)
|
||||||
{
|
{
|
||||||
char* temp = (char*)alloca(strlen(format)+512);
|
char* temp = (char*)alloca(strlen(format)+512);
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
CharArrayFromFormatV(temp, 512, format, args);
|
CharArrayFromFormatV(temp, 512, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
LogManager::Log((LogTypes::LOG_TYPE)(log + v*100), temp);
|
LogManager::Log((LogTypes::LOG_TYPE)(log + v*100), temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
CDebugger_Log::CDebugger_Log(const char* _szShortName, const char* _szName, int a) :
|
CDebugger_Log::CDebugger_Log(const char* _szShortName, const char* _szName, int a) :
|
||||||
m_bLogToFile(true), // write to file or not
|
m_bLogToFile(true), // write to file or not
|
||||||
m_bShowInLog(false),
|
m_bShowInLog(false),
|
||||||
m_bEnable(false),
|
m_bEnable(false),
|
||||||
m_pFile(NULL)
|
m_pFile(NULL)
|
||||||
{
|
{
|
||||||
strcpy((char*)m_szName, _szName);
|
strcpy((char*)m_szName, _szName);
|
||||||
strcpy((char*)m_szShortName_, _szShortName);
|
strcpy((char*)m_szShortName_, _szShortName);
|
||||||
sprintf((char*)m_szShortName, "%s%i", _szShortName, a);
|
sprintf((char*)m_szShortName, "%s%i", _szShortName, a);
|
||||||
sprintf((char*)m_szFilename, FULL_LOGS_DIR "%s%i.txt", _szName, a);
|
sprintf((char*)m_szFilename, FULL_LOGS_DIR "%s%i.txt", _szName, a);
|
||||||
|
|
||||||
unlink(m_szFilename);
|
unlink(m_szFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
CDebugger_Log::~CDebugger_Log(void)
|
CDebugger_Log::~CDebugger_Log(void)
|
||||||
{
|
{
|
||||||
if (m_pFile)
|
if (m_pFile)
|
||||||
{
|
{
|
||||||
fclose(m_pFile);
|
fclose(m_pFile);
|
||||||
m_pFile = NULL;
|
m_pFile = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we may need to declare these
|
// we may need to declare these
|
||||||
CDebugger_LogSettings::CDebugger_LogSettings() {}
|
CDebugger_LogSettings::CDebugger_LogSettings() {}
|
||||||
CDebugger_LogSettings::~CDebugger_LogSettings(void) {}
|
CDebugger_LogSettings::~CDebugger_LogSettings(void) {}
|
||||||
|
|
||||||
void CDebugger_Log::Init()
|
void CDebugger_Log::Init()
|
||||||
{
|
{
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
m_pFile = fopen(m_szFilename, "wtb");
|
m_pFile = fopen(m_szFilename, "wtb");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDebugger_Log::Shutdown()
|
void CDebugger_Log::Shutdown()
|
||||||
{
|
{
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
if (m_pFile != NULL)
|
if (m_pFile != NULL)
|
||||||
{
|
{
|
||||||
fclose(m_pFile);
|
fclose(m_pFile);
|
||||||
m_pFile = NULL;
|
m_pFile = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LogManager::Init()
|
void LogManager::Init()
|
||||||
{
|
{
|
||||||
m_Messages = new SMessage[LogManager::VERBOSITY_LEVELS + 1][MAX_MESSAGES];
|
m_Messages = new SMessage[LogManager::VERBOSITY_LEVELS + 1][MAX_MESSAGES];
|
||||||
m_bDirty = true;
|
m_bDirty = true;
|
||||||
|
|
||||||
// create log files
|
// create log files
|
||||||
for(int i = 0; i <= LogManager::VERBOSITY_LEVELS; i++)
|
for(int i = 0; i <= LogManager::VERBOSITY_LEVELS; i++)
|
||||||
{
|
{
|
||||||
m_Log[LogTypes::MASTER_LOG + i*100] = new CDebugger_Log("*", "Master Log", i);
|
m_Log[LogTypes::MASTER_LOG + i*100] = new CDebugger_Log("*", "Master Log", i);
|
||||||
m_Log[LogTypes::BOOT + i*100] = new CDebugger_Log("BOOT", "Boot", i);
|
m_Log[LogTypes::BOOT + i*100] = new CDebugger_Log("BOOT", "Boot", i);
|
||||||
m_Log[LogTypes::PIXELENGINE + i*100] = new CDebugger_Log("PE", "PixelEngine", i);
|
m_Log[LogTypes::PIXELENGINE + i*100] = new CDebugger_Log("PE", "PixelEngine", i);
|
||||||
m_Log[LogTypes::COMMANDPROCESSOR + i*100] = new CDebugger_Log("CP", "CommandProc", i);
|
m_Log[LogTypes::COMMANDPROCESSOR + i*100] = new CDebugger_Log("CP", "CommandProc", i);
|
||||||
m_Log[LogTypes::VIDEOINTERFACE + i*100] = new CDebugger_Log("VI", "VideoInt", i);
|
m_Log[LogTypes::VIDEOINTERFACE + i*100] = new CDebugger_Log("VI", "VideoInt", i);
|
||||||
m_Log[LogTypes::SERIALINTERFACE + i*100] = new CDebugger_Log("SI", "SerialInt", i);
|
m_Log[LogTypes::SERIALINTERFACE + i*100] = new CDebugger_Log("SI", "SerialInt", i);
|
||||||
m_Log[LogTypes::PERIPHERALINTERFACE + i*100]= new CDebugger_Log("PI", "PeripheralInt", i);
|
m_Log[LogTypes::PERIPHERALINTERFACE + i*100]= new CDebugger_Log("PI", "PeripheralInt", i);
|
||||||
m_Log[LogTypes::MEMMAP + i*100] = new CDebugger_Log("MI", "MI & memmap", i);
|
m_Log[LogTypes::MEMMAP + i*100] = new CDebugger_Log("MI", "MI & memmap", i);
|
||||||
m_Log[LogTypes::STREAMINGINTERFACE + i*100] = new CDebugger_Log("Stream", "StreamingInt", i);
|
m_Log[LogTypes::STREAMINGINTERFACE + i*100] = new CDebugger_Log("Stream", "StreamingInt", i);
|
||||||
m_Log[LogTypes::DSPINTERFACE + i*100] = new CDebugger_Log("DSP", "DSPInterface", i);
|
m_Log[LogTypes::DSPINTERFACE + i*100] = new CDebugger_Log("DSP", "DSPInterface", i);
|
||||||
m_Log[LogTypes::DVDINTERFACE + i*100] = new CDebugger_Log("DVD", "DVDInterface", i);
|
m_Log[LogTypes::DVDINTERFACE + i*100] = new CDebugger_Log("DVD", "DVDInterface", i);
|
||||||
m_Log[LogTypes::GPFIFO + i*100] = new CDebugger_Log("GP", "GPFifo", i);
|
m_Log[LogTypes::GPFIFO + i*100] = new CDebugger_Log("GP", "GPFifo", i);
|
||||||
m_Log[LogTypes::EXPANSIONINTERFACE + i*100] = new CDebugger_Log("EXI", "ExpansionInt", i);
|
m_Log[LogTypes::EXPANSIONINTERFACE + i*100] = new CDebugger_Log("EXI", "ExpansionInt", i);
|
||||||
m_Log[LogTypes::AUDIO_INTERFACE + i*100] = new CDebugger_Log("AI", "AudioInt", i);
|
m_Log[LogTypes::AUDIO_INTERFACE + i*100] = new CDebugger_Log("AI", "AudioInt", i);
|
||||||
m_Log[LogTypes::GEKKO + i*100] = new CDebugger_Log("GEKKO", "IBM CPU", i);
|
m_Log[LogTypes::GEKKO + i*100] = new CDebugger_Log("GEKKO", "IBM CPU", i);
|
||||||
m_Log[LogTypes::HLE + i*100] = new CDebugger_Log("HLE", "HLE", i);
|
m_Log[LogTypes::HLE + i*100] = new CDebugger_Log("HLE", "HLE", i);
|
||||||
m_Log[LogTypes::DSPHLE + i*100] = new CDebugger_Log("DSPHLE", "DSP HLE", i);
|
m_Log[LogTypes::DSPHLE + i*100] = new CDebugger_Log("DSPHLE", "DSP HLE", i);
|
||||||
m_Log[LogTypes::VIDEO + i*100] = new CDebugger_Log("Video", "Video Plugin", i);
|
m_Log[LogTypes::VIDEO + i*100] = new CDebugger_Log("Video", "Video Plugin", i);
|
||||||
m_Log[LogTypes::AUDIO + i*100] = new CDebugger_Log("Audio", "Audio Plugin", i);
|
m_Log[LogTypes::AUDIO + i*100] = new CDebugger_Log("Audio", "Audio Plugin", i);
|
||||||
m_Log[LogTypes::DYNA_REC + i*100] = new CDebugger_Log("DYNA", "Dynamic Recompiler", i);
|
m_Log[LogTypes::DYNA_REC + i*100] = new CDebugger_Log("DYNA", "Dynamic Recompiler", i);
|
||||||
m_Log[LogTypes::CONSOLE + i*100] = new CDebugger_Log("CONSOLE", "Dolphin Console", i);
|
m_Log[LogTypes::CONSOLE + i*100] = new CDebugger_Log("CONSOLE", "Dolphin Console", i);
|
||||||
m_Log[LogTypes::OSREPORT + i*100] = new CDebugger_Log("OSREPORT", "OSReport", i);
|
m_Log[LogTypes::OSREPORT + i*100] = new CDebugger_Log("OSREPORT", "OSReport", i);
|
||||||
m_Log[LogTypes::WII_IOB + i*100] = new CDebugger_Log("WII_IOB", "WII IO Bridge", i);
|
m_Log[LogTypes::WII_IOB + i*100] = new CDebugger_Log("WII_IOB", "WII IO Bridge", i);
|
||||||
m_Log[LogTypes::WII_IPC + i*100] = new CDebugger_Log("WII_IPC", "WII IPC", i);
|
m_Log[LogTypes::WII_IPC + i*100] = new CDebugger_Log("WII_IPC", "WII IPC", i);
|
||||||
m_Log[LogTypes::WII_IPC_HLE + i*100] = new CDebugger_Log("WII_IPC_HLE", "WII IPC HLE", i);
|
m_Log[LogTypes::WII_IPC_HLE + i*100] = new CDebugger_Log("WII_IPC_HLE", "WII IPC HLE", i);
|
||||||
m_Log[LogTypes::WII_IPC_DVD + i*100] = new CDebugger_Log("WII_IPC_DVD", "WII IPC DVD", i);
|
m_Log[LogTypes::WII_IPC_DVD + i*100] = new CDebugger_Log("WII_IPC_DVD", "WII IPC DVD", i);
|
||||||
m_Log[LogTypes::WII_IPC_ES + i*100] = new CDebugger_Log("WII_IPC_ES", "WII IPC ES", i);
|
m_Log[LogTypes::WII_IPC_ES + i*100] = new CDebugger_Log("WII_IPC_ES", "WII IPC ES", i);
|
||||||
m_Log[LogTypes::WII_IPC_FILEIO + i*100] = new CDebugger_Log("WII_IPC_FILEIO", "WII IPC FILEIO", i);
|
m_Log[LogTypes::WII_IPC_FILEIO + i*100] = new CDebugger_Log("WII_IPC_FILEIO", "WII IPC FILEIO", i);
|
||||||
m_Log[LogTypes::WII_IPC_SD + i*100] = new CDebugger_Log("WII_IPC_SD", "WII IPC SD", i);
|
m_Log[LogTypes::WII_IPC_SD + i*100] = new CDebugger_Log("WII_IPC_SD", "WII IPC SD", i);
|
||||||
m_Log[LogTypes::WII_IPC_NET + i*100] = new CDebugger_Log("WII_IPC_NET", "WII IPC NET", i);
|
m_Log[LogTypes::WII_IPC_NET + i*100] = new CDebugger_Log("WII_IPC_NET", "WII IPC NET", i);
|
||||||
m_Log[LogTypes::WII_IPC_WIIMOTE + i*100] = new CDebugger_Log("WII_IPC_WIIMOTE", "WII IPC WIIMOTE", i);
|
m_Log[LogTypes::WII_IPC_WIIMOTE + i*100] = new CDebugger_Log("WII_IPC_WIIMOTE", "WII IPC WIIMOTE", i);
|
||||||
m_Log[LogTypes::ACTIONREPLAY + i*100] = new CDebugger_Log("ActionReplay", "ActionReplay", i);
|
m_Log[LogTypes::ACTIONREPLAY + i*100] = new CDebugger_Log("ActionReplay", "ActionReplay", i);
|
||||||
|
|
||||||
m_nextMessages[i] = 0; // initiate to zero
|
m_nextMessages[i] = 0; // initiate to zero
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the files
|
// create the files
|
||||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
|
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j <= LogManager::VERBOSITY_LEVELS; j++)
|
for (int j = 0; j <= LogManager::VERBOSITY_LEVELS; j++)
|
||||||
{
|
{
|
||||||
m_Log[j*100 + i]->Init();
|
m_Log[j*100 + i]->Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_bInitialized = true;
|
m_bInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LogManager::Clear()
|
void LogManager::Clear()
|
||||||
{
|
{
|
||||||
for (int v = 0; v <= LogManager::VERBOSITY_LEVELS; v++)
|
for (int v = 0; v <= LogManager::VERBOSITY_LEVELS; v++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAX_MESSAGES; i++)
|
for (int i = 0; i < MAX_MESSAGES; i++)
|
||||||
{
|
{
|
||||||
strcpy(m_Messages[v][i].m_szMessage,"");
|
strcpy(m_Messages[v][i].m_szMessage,"");
|
||||||
m_Messages[v][i].m_dwMsgLen = 0;
|
m_Messages[v][i].m_dwMsgLen = 0;
|
||||||
m_Messages[v][i].m_bInUse = false;
|
m_Messages[v][i].m_bInUse = false;
|
||||||
}
|
}
|
||||||
m_nextMessages[v] = 0;
|
m_nextMessages[v] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
// Shutdown
|
// Shutdown
|
||||||
//
|
//
|
||||||
void LogManager::Shutdown()
|
void LogManager::Shutdown()
|
||||||
{
|
{
|
||||||
m_bInitialized = false;
|
m_bInitialized = false;
|
||||||
|
|
||||||
// delete all loggers
|
// delete all loggers
|
||||||
for (int i=0; i<LogTypes::NUMBER_OF_LOGS; i++)
|
for (int i=0; i<LogTypes::NUMBER_OF_LOGS; i++)
|
||||||
{
|
{
|
||||||
if (m_Log[i] != NULL)
|
if (m_Log[i] != NULL)
|
||||||
{
|
{
|
||||||
m_Log[i]->Shutdown();
|
m_Log[i]->Shutdown();
|
||||||
delete m_Log[i];
|
delete m_Log[i];
|
||||||
m_Log[i] = NULL;
|
m_Log[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete [] m_Messages;
|
delete [] m_Messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ==========================================================================================
|
// ==========================================================================================
|
||||||
// The function that finally writes the log.
|
// The function that finally writes the log.
|
||||||
// ---------------
|
// ---------------
|
||||||
u32 lastPC;
|
u32 lastPC;
|
||||||
std::string lastSymbol;
|
std::string lastSymbol;
|
||||||
void LogManager::Log(LogTypes::LOG_TYPE _type, const char *_fmt, ...)
|
void LogManager::Log(LogTypes::LOG_TYPE _type, const char *_fmt, ...)
|
||||||
{
|
{
|
||||||
if (m_LogSettings == NULL)
|
if (m_LogSettings == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// declarations
|
// declarations
|
||||||
int v; // verbosity level
|
int v; // verbosity level
|
||||||
int type; // the log type, CONSOLE etc.
|
int type; // the log type, CONSOLE etc.
|
||||||
char cvv[20];
|
char cvv[20];
|
||||||
std::string svv;
|
std::string svv;
|
||||||
|
|
||||||
// get the current verbosity level and type
|
// get the current verbosity level and type
|
||||||
sprintf(cvv, "%03i", (int)_type);
|
sprintf(cvv, "%03i", (int)_type);
|
||||||
svv = cvv;
|
svv = cvv;
|
||||||
v = atoi(svv.substr(0, 1).c_str());
|
v = atoi(svv.substr(0, 1).c_str());
|
||||||
type = atoi(svv.substr(1, 2).c_str());
|
type = atoi(svv.substr(1, 2).c_str());
|
||||||
|
|
||||||
// security checks
|
// security checks
|
||||||
if (m_Log[_type] == NULL || !m_Log[_type]->m_bEnable || PC == 0
|
if (m_Log[_type] == NULL || !m_Log[_type]->m_bEnable || PC == 0
|
||||||
|| _type > (LogTypes::NUMBER_OF_LOGS + LogManager::VERBOSITY_LEVELS * 100)
|
|| _type > (LogTypes::NUMBER_OF_LOGS + LogManager::VERBOSITY_LEVELS * 100)
|
||||||
|| _type < 0)
|
|| _type < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// prepare message
|
// prepare message
|
||||||
char Msg[512];
|
char Msg[512];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, _fmt);
|
va_start(ap, _fmt);
|
||||||
vsprintf(Msg, _fmt, ap);
|
vsprintf(Msg, _fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
static u32 count = 0;
|
static u32 count = 0;
|
||||||
#if defined(HAVE_WX) && HAVE_WX
|
#if defined(HAVE_WX) && HAVE_WX
|
||||||
wxDateTime datetime = wxDateTime::UNow(); // get timestamp
|
wxDateTime datetime = wxDateTime::UNow(); // get timestamp
|
||||||
#endif
|
#endif
|
||||||
char* Msg2 = (char*)alloca(strlen(_fmt)+512);
|
char* Msg2 = (char*)alloca(strlen(_fmt)+512);
|
||||||
|
|
||||||
// Here's the old symbol request
|
// Here's the old symbol request
|
||||||
//Debugger::FindSymbol(PC);
|
//Debugger::FindSymbol(PC);
|
||||||
// const Debugger::Symbol& symbol = Debugger::GetSymbol(Index);
|
// const Debugger::Symbol& symbol = Debugger::GetSymbol(Index);
|
||||||
//symbol.GetName().c_str(),
|
//symbol.GetName().c_str(),
|
||||||
|
|
||||||
// Warning: Getting the function name this often is very demanding on the CPU.
|
// Warning: Getting the function name this often is very demanding on the CPU.
|
||||||
// I have limited it to the two lowest verbosity levels because of that. I've also
|
// I have limited it to the two lowest verbosity levels because of that. I've also
|
||||||
// added a simple caching function so that we don't search again if we get the same
|
// added a simple caching function so that we don't search again if we get the same
|
||||||
// question again.
|
// question again.
|
||||||
std::string symbol;
|
std::string symbol;
|
||||||
|
|
||||||
if ((v == 0 || v == 1) && lastPC != PC && LogManager::m_LogSettings->bResolve)
|
if ((v == 0 || v == 1) && lastPC != PC && LogManager::m_LogSettings->bResolve)
|
||||||
{
|
{
|
||||||
symbol = g_symbolDB.GetDescription(PC);
|
symbol = g_symbolDB.GetDescription(PC);
|
||||||
lastSymbol = symbol;
|
lastSymbol = symbol;
|
||||||
lastPC = PC;
|
lastPC = PC;
|
||||||
}
|
}
|
||||||
else if(lastPC == PC && LogManager::m_LogSettings->bResolve)
|
else if(lastPC == PC && LogManager::m_LogSettings->bResolve)
|
||||||
{
|
{
|
||||||
symbol = lastSymbol;
|
symbol = lastSymbol;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
symbol = "---";
|
symbol = "---";
|
||||||
}
|
}
|
||||||
|
|
||||||
int Index = 1;
|
int Index = 1;
|
||||||
const char *eol = "\n";
|
const char *eol = "\n";
|
||||||
if (Index > 0)
|
if (Index > 0)
|
||||||
{
|
{
|
||||||
//sprintf(Msg2, "%i | %i %02i:%02i:%03i: %x %s (%s, %08x) : %s%s",
|
//sprintf(Msg2, "%i | %i %02i:%02i:%03i: %x %s (%s, %08x) : %s%s",
|
||||||
sprintf(Msg2, "%i %02i:%02i:%03i: %x %s (%s, %08x) : %s%s",
|
sprintf(Msg2, "%i %02i:%02i:%03i: %x %s (%s, %08x) : %s%s",
|
||||||
//v,
|
//v,
|
||||||
++count,
|
++count,
|
||||||
#if defined(HAVE_WX) && HAVE_WX
|
#if defined(HAVE_WX) && HAVE_WX
|
||||||
datetime.GetMinute(), datetime.GetSecond(), datetime.GetMillisecond(),
|
datetime.GetMinute(), datetime.GetSecond(), datetime.GetMillisecond(),
|
||||||
#else
|
#else
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
// TODO get proper values
|
// TODO get proper values
|
||||||
#endif
|
#endif
|
||||||
PowerPC::ppcState.DebugCount,
|
PowerPC::ppcState.DebugCount,
|
||||||
m_Log[_type]->m_szShortName_, // (CONSOLE etc)
|
m_Log[_type]->m_szShortName_, // (CONSOLE etc)
|
||||||
symbol.c_str(), PC, // current PC location (name, address)
|
symbol.c_str(), PC, // current PC location (name, address)
|
||||||
Msg, eol);
|
Msg, eol);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================================================================
|
// ==========================================================================================
|
||||||
/* Here we have two options
|
/* Here we have two options
|
||||||
1. Verbosity mode where level 0 verbosity logs will be written to all verbosity
|
1. Verbosity mode where level 0 verbosity logs will be written to all verbosity
|
||||||
levels. Given that logging is enabled for that level. Level 1 verbosity will
|
levels. Given that logging is enabled for that level. Level 1 verbosity will
|
||||||
only be written to level 1, 2, 3 and so on.
|
only be written to level 1, 2, 3 and so on.
|
||||||
2. Unify mode where everything is written to the last message struct and the
|
2. Unify mode where everything is written to the last message struct and the
|
||||||
last file */
|
last file */
|
||||||
// ---------------
|
// ---------------
|
||||||
|
|
||||||
// Check if we should do a unified write to a single file
|
// Check if we should do a unified write to a single file
|
||||||
if(m_LogSettings->bUnify)
|
if(m_LogSettings->bUnify)
|
||||||
{
|
{
|
||||||
// prepare the right id
|
// prepare the right id
|
||||||
int id = VERBOSITY_LEVELS*100 + type;
|
int id = VERBOSITY_LEVELS*100 + type;
|
||||||
int ver = VERBOSITY_LEVELS;
|
int ver = VERBOSITY_LEVELS;
|
||||||
|
|
||||||
// write to memory
|
// write to memory
|
||||||
m_Messages[ver][m_nextMessages[ver]].Set((LogTypes::LOG_TYPE)id, v, Msg2);
|
m_Messages[ver][m_nextMessages[ver]].Set((LogTypes::LOG_TYPE)id, v, Msg2);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
// Write to file
|
// Write to file
|
||||||
// ---------------
|
// ---------------
|
||||||
if (m_Log[id]->m_pFile && m_Log[id]->m_bLogToFile)
|
if (m_Log[id]->m_pFile && m_Log[id]->m_bLogToFile)
|
||||||
fprintf(m_Log[id]->m_pFile, "%s", Msg2);
|
fprintf(m_Log[id]->m_pFile, "%s", Msg2);
|
||||||
if (m_Log[ver*100 + LogTypes::MASTER_LOG] && m_Log[ver*100 + LogTypes::MASTER_LOG]->m_pFile
|
if (m_Log[ver*100 + LogTypes::MASTER_LOG] && m_Log[ver*100 + LogTypes::MASTER_LOG]->m_pFile
|
||||||
&& m_LogSettings->bWriteMaster)
|
&& m_LogSettings->bWriteMaster)
|
||||||
fprintf(m_Log[ver*100 + LogTypes::MASTER_LOG]->m_pFile, "%s", Msg2);
|
fprintf(m_Log[ver*100 + LogTypes::MASTER_LOG]->m_pFile, "%s", Msg2);
|
||||||
|
|
||||||
/* In case it crashes write now to make sure you get the last messages.
|
/* In case it crashes write now to make sure you get the last messages.
|
||||||
Is this slower than caching it? */
|
Is this slower than caching it? */
|
||||||
//fflush(m_Log[id]->m_pFile);
|
//fflush(m_Log[id]->m_pFile);
|
||||||
//fflush(m_Log[ver*100 + LogTypes::MASTER_LOG]->m_pFile);
|
//fflush(m_Log[ver*100 + LogTypes::MASTER_LOG]->m_pFile);
|
||||||
|
|
||||||
printf("%s", Msg2); // write to console screen
|
printf("%s", Msg2); // write to console screen
|
||||||
|
|
||||||
// this limits the memory space used for the memory logs to MAX_MESSAGES rows
|
// this limits the memory space used for the memory logs to MAX_MESSAGES rows
|
||||||
m_nextMessages[ver]++;
|
m_nextMessages[ver]++;
|
||||||
if (m_nextMessages[ver] >= MAX_MESSAGES)
|
if (m_nextMessages[ver] >= MAX_MESSAGES)
|
||||||
m_nextMessages[ver] = 0;
|
m_nextMessages[ver] = 0;
|
||||||
// ---------------
|
// ---------------
|
||||||
}
|
}
|
||||||
else // write to separate files and structs
|
else // write to separate files and structs
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
for (int i = VERBOSITY_LEVELS; i >= v ; i--)
|
for (int i = VERBOSITY_LEVELS; i >= v ; i--)
|
||||||
{
|
{
|
||||||
// prepare the right id
|
// prepare the right id
|
||||||
id = i*100 + type;
|
id = i*100 + type;
|
||||||
|
|
||||||
// write to memory
|
// write to memory
|
||||||
m_Messages[i][m_nextMessages[i]].Set((LogTypes::LOG_TYPE)id, v, Msg2);
|
m_Messages[i][m_nextMessages[i]].Set((LogTypes::LOG_TYPE)id, v, Msg2);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
// Write to file
|
// Write to file
|
||||||
// ---------------
|
// ---------------
|
||||||
if (m_Log[id]->m_pFile && m_Log[id]->m_bLogToFile)
|
if (m_Log[id]->m_pFile && m_Log[id]->m_bLogToFile)
|
||||||
fprintf(m_Log[id]->m_pFile, "%s", Msg2);
|
fprintf(m_Log[id]->m_pFile, "%s", Msg2);
|
||||||
if (m_Log[i*100 + LogTypes::MASTER_LOG] && m_Log[i*100 + LogTypes::MASTER_LOG]->m_pFile
|
if (m_Log[i*100 + LogTypes::MASTER_LOG] && m_Log[i*100 + LogTypes::MASTER_LOG]->m_pFile
|
||||||
&& m_LogSettings->bWriteMaster)
|
&& m_LogSettings->bWriteMaster)
|
||||||
fprintf(m_Log[i*100 + LogTypes::MASTER_LOG]->m_pFile, "%s", Msg2);
|
fprintf(m_Log[i*100 + LogTypes::MASTER_LOG]->m_pFile, "%s", Msg2);
|
||||||
|
|
||||||
// Write now. Is this slower than caching it?
|
// Write now. Is this slower than caching it?
|
||||||
//fflush(m_Log[id]->m_pFile);
|
//fflush(m_Log[id]->m_pFile);
|
||||||
//fflush(m_Log[i*100 + LogTypes::MASTER_LOG]->m_pFile);
|
//fflush(m_Log[i*100 + LogTypes::MASTER_LOG]->m_pFile);
|
||||||
|
|
||||||
printf("%s", Msg2); // write to console screen
|
printf("%s", Msg2); // write to console screen
|
||||||
|
|
||||||
// this limits the memory space used for the memory logs to MAX_MESSAGES rows
|
// this limits the memory space used for the memory logs to MAX_MESSAGES rows
|
||||||
m_nextMessages[i]++;
|
m_nextMessages[i]++;
|
||||||
if (m_nextMessages[i] >= MAX_MESSAGES)
|
if (m_nextMessages[i] >= MAX_MESSAGES)
|
||||||
m_nextMessages[i] = 0;
|
m_nextMessages[i] = 0;
|
||||||
// ---------------
|
// ---------------
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_bDirty = true; // tell LogWindow that the log has been updated
|
m_bDirty = true; // tell LogWindow that the log has been updated
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsLoggingActivated()
|
bool IsLoggingActivated()
|
||||||
{
|
{
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,220 +1,220 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
|
|
||||||
// TODO: create a working OS-neutral version of this file and put it in Common.
|
// TODO: create a working OS-neutral version of this file and put it in Common.
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "MemTools.h"
|
#include "MemTools.h"
|
||||||
#include "HW/Memmap.h"
|
#include "HW/Memmap.h"
|
||||||
#include "PowerPC/PowerPC.h"
|
#include "PowerPC/PowerPC.h"
|
||||||
#include "PowerPC/Jit64/Jit.h"
|
#include "PowerPC/Jit64/Jit.h"
|
||||||
#include "PowerPC/Jit64/JitBackpatch.h"
|
#include "PowerPC/Jit64/JitBackpatch.h"
|
||||||
#include "x64Analyzer.h"
|
#include "x64Analyzer.h"
|
||||||
|
|
||||||
namespace EMM
|
namespace EMM
|
||||||
{
|
{
|
||||||
|
|
||||||
LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
|
LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
|
||||||
{
|
{
|
||||||
switch (pPtrs->ExceptionRecord->ExceptionCode)
|
switch (pPtrs->ExceptionRecord->ExceptionCode)
|
||||||
{
|
{
|
||||||
case EXCEPTION_ACCESS_VIOLATION:
|
case EXCEPTION_ACCESS_VIOLATION:
|
||||||
{
|
{
|
||||||
int accessType = (int)pPtrs->ExceptionRecord->ExceptionInformation[0];
|
int accessType = (int)pPtrs->ExceptionRecord->ExceptionInformation[0];
|
||||||
if (accessType == 8) //Rule out DEP
|
if (accessType == 8) //Rule out DEP
|
||||||
{
|
{
|
||||||
if(PowerPC::state == PowerPC::CPU_POWERDOWN) // Access violation during
|
if(PowerPC::state == PowerPC::CPU_POWERDOWN) // Access violation during
|
||||||
// violent shutdown is fine
|
// violent shutdown is fine
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
|
|
||||||
MessageBox(0, _T("Tried to execute code that's not marked executable. This is likely a JIT bug.\n"), 0, 0);
|
MessageBox(0, _T("Tried to execute code that's not marked executable. This is likely a JIT bug.\n"), 0, 0);
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Where in the x86 code are we?
|
//Where in the x86 code are we?
|
||||||
PVOID codeAddr = pPtrs->ExceptionRecord->ExceptionAddress;
|
PVOID codeAddr = pPtrs->ExceptionRecord->ExceptionAddress;
|
||||||
unsigned char *codePtr = (unsigned char*)codeAddr;
|
unsigned char *codePtr = (unsigned char*)codeAddr;
|
||||||
|
|
||||||
if (!Jit64::IsInJitCode(codePtr)) {
|
if (!Jit64::IsInJitCode(codePtr)) {
|
||||||
// Let's not prevent debugging.
|
// Let's not prevent debugging.
|
||||||
return (DWORD)EXCEPTION_CONTINUE_SEARCH;
|
return (DWORD)EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Figure out what address was hit
|
//Figure out what address was hit
|
||||||
u64 badAddress = (u64)pPtrs->ExceptionRecord->ExceptionInformation[1];
|
u64 badAddress = (u64)pPtrs->ExceptionRecord->ExceptionInformation[1];
|
||||||
//TODO: First examine the address, make sure it's within the emulated memory space
|
//TODO: First examine the address, make sure it's within the emulated memory space
|
||||||
u64 memspaceBottom = (u64)Memory::base;
|
u64 memspaceBottom = (u64)Memory::base;
|
||||||
if (badAddress < memspaceBottom) {
|
if (badAddress < memspaceBottom) {
|
||||||
PanicAlert("Exception handler - access below memory space. %08x%08x",
|
PanicAlert("Exception handler - access below memory space. %08x%08x",
|
||||||
badAddress >> 32, badAddress);
|
badAddress >> 32, badAddress);
|
||||||
}
|
}
|
||||||
u32 emAddress = (u32)(badAddress - memspaceBottom);
|
u32 emAddress = (u32)(badAddress - memspaceBottom);
|
||||||
|
|
||||||
//Now we have the emulated address.
|
//Now we have the emulated address.
|
||||||
//Let's notify everyone who wants to be notified
|
//Let's notify everyone who wants to be notified
|
||||||
//Notify(emAddress, accessType == 0 ? Read : Write);
|
//Notify(emAddress, accessType == 0 ? Read : Write);
|
||||||
|
|
||||||
CONTEXT *ctx = pPtrs->ContextRecord;
|
CONTEXT *ctx = pPtrs->ContextRecord;
|
||||||
//opportunity to play with the context - we can change the debug regs!
|
//opportunity to play with the context - we can change the debug regs!
|
||||||
|
|
||||||
//We could emulate the memory accesses here, but then they would still be around to take up
|
//We could emulate the memory accesses here, but then they would still be around to take up
|
||||||
//execution resources. Instead, we backpatch into a generic memory call and retry.
|
//execution resources. Instead, we backpatch into a generic memory call and retry.
|
||||||
u8 *new_rip = Jit64::BackPatch(codePtr, accessType, emAddress, ctx);
|
u8 *new_rip = Jit64::BackPatch(codePtr, accessType, emAddress, ctx);
|
||||||
|
|
||||||
// We no longer touch Rip, since we return back to the instruction, after overwriting it with a
|
// We no longer touch Rip, since we return back to the instruction, after overwriting it with a
|
||||||
// trampoline jump and some nops
|
// trampoline jump and some nops
|
||||||
if (new_rip)
|
if (new_rip)
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
ctx->Rip = (DWORD_PTR)new_rip;
|
ctx->Rip = (DWORD_PTR)new_rip;
|
||||||
#else
|
#else
|
||||||
ctx->Eip = (DWORD_PTR)new_rip;
|
ctx->Eip = (DWORD_PTR)new_rip;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return (DWORD)EXCEPTION_CONTINUE_EXECUTION;
|
return (DWORD)EXCEPTION_CONTINUE_EXECUTION;
|
||||||
|
|
||||||
case EXCEPTION_STACK_OVERFLOW:
|
case EXCEPTION_STACK_OVERFLOW:
|
||||||
MessageBox(0, _T("Stack overflow!"), 0,0);
|
MessageBox(0, _T("Stack overflow!"), 0,0);
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
|
||||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||||
//No SSE support? Or simply bad codegen?
|
//No SSE support? Or simply bad codegen?
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
|
||||||
case EXCEPTION_PRIV_INSTRUCTION:
|
case EXCEPTION_PRIV_INSTRUCTION:
|
||||||
//okay, dynarec codegen is obviously broken.
|
//okay, dynarec codegen is obviously broken.
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
|
||||||
case EXCEPTION_IN_PAGE_ERROR:
|
case EXCEPTION_IN_PAGE_ERROR:
|
||||||
//okay, something went seriously wrong, out of memory?
|
//okay, something went seriously wrong, out of memory?
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
|
||||||
case EXCEPTION_BREAKPOINT:
|
case EXCEPTION_BREAKPOINT:
|
||||||
//might want to do something fun with this one day?
|
//might want to do something fun with this one day?
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstallExceptionHandler()
|
void InstallExceptionHandler()
|
||||||
{
|
{
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
// Make sure this is only called once per process execution
|
// Make sure this is only called once per process execution
|
||||||
// Instead, could make a Uninstall function, but whatever..
|
// Instead, could make a Uninstall function, but whatever..
|
||||||
static bool handlerInstalled = false;
|
static bool handlerInstalled = false;
|
||||||
if (handlerInstalled)
|
if (handlerInstalled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AddVectoredExceptionHandler(TRUE, Handler);
|
AddVectoredExceptionHandler(TRUE, Handler);
|
||||||
handlerInstalled = true;
|
handlerInstalled = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
namespace EMM {
|
namespace EMM {
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
//
|
//
|
||||||
// backtrace useful function
|
// backtrace useful function
|
||||||
//
|
//
|
||||||
void print_trace(const char * msg)
|
void print_trace(const char * msg)
|
||||||
{
|
{
|
||||||
void *array[100];
|
void *array[100];
|
||||||
size_t size;
|
size_t size;
|
||||||
char **strings;
|
char **strings;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
size = backtrace(array, 100);
|
size = backtrace(array, 100);
|
||||||
strings = backtrace_symbols(array, size);
|
strings = backtrace_symbols(array, size);
|
||||||
printf("%s Obtained %zd stack frames.\n", msg, size);
|
printf("%s Obtained %zd stack frames.\n", msg, size);
|
||||||
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++)
|
||||||
printf("--> %s\n", strings[i]);
|
printf("--> %s\n", strings[i]);
|
||||||
free(strings);
|
free(strings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sigsegv_handler(int signal, int siginfo_t *info, void *raw_context)
|
void sigsegv_handler(int signal, int siginfo_t *info, void *raw_context)
|
||||||
{
|
{
|
||||||
if (signal != SIGSEGV)
|
if (signal != SIGSEGV)
|
||||||
{
|
{
|
||||||
// We are not interested in other signals - handle it as usual.
|
// We are not interested in other signals - handle it as usual.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ucontext_t *context = (ucontext_t)raw_context;
|
ucontext_t *context = (ucontext_t)raw_context;
|
||||||
int si_code = info->si_code;
|
int si_code = info->si_code;
|
||||||
if (si_code != SEGV_MAPERR)
|
if (si_code != SEGV_MAPERR)
|
||||||
{
|
{
|
||||||
// Huh? Return.
|
// Huh? Return.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mcontext_t *ctx = &context->uc_mcontext;
|
mcontext_t *ctx = &context->uc_mcontext;
|
||||||
void *fault_memory_ptr = (void *)info->si_addr;
|
void *fault_memory_ptr = (void *)info->si_addr;
|
||||||
void *fault_instruction_ptr = (void *)ctx->mc_rip;
|
void *fault_instruction_ptr = (void *)ctx->mc_rip;
|
||||||
|
|
||||||
if (!Jit64::IsInJitCode(fault_instruction_ptr)) {
|
if (!Jit64::IsInJitCode(fault_instruction_ptr)) {
|
||||||
// Let's not prevent debugging.
|
// Let's not prevent debugging.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 memspaceBottom = (u64)Memory::base;
|
u64 memspaceBottom = (u64)Memory::base;
|
||||||
if (badAddress < memspaceBottom) {
|
if (badAddress < memspaceBottom) {
|
||||||
PanicAlert("Exception handler - access below memory space. %08x%08x",
|
PanicAlert("Exception handler - access below memory space. %08x%08x",
|
||||||
badAddress >> 32, badAddress);
|
badAddress >> 32, badAddress);
|
||||||
}
|
}
|
||||||
u32 emAddress = (u32)(badAddress - memspaceBottom);
|
u32 emAddress = (u32)(badAddress - memspaceBottom);
|
||||||
|
|
||||||
// Backpatch time.
|
// Backpatch time.
|
||||||
Jit64::BackPatch(fault_instruction_ptr, accessType, emAddress);
|
Jit64::BackPatch(fault_instruction_ptr, accessType, emAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void InstallExceptionHandler()
|
void InstallExceptionHandler()
|
||||||
{
|
{
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
PanicAlert("InstallExceptionHandler called, but this platform does not yet support it.");
|
PanicAlert("InstallExceptionHandler called, but this platform does not yet support it.");
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
sighandler_t old_signal_handler = signal(SIGSEGV , sigsegv_handler);
|
sighandler_t old_signal_handler = signal(SIGSEGV , sigsegv_handler);
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
memset(&sa, 0, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sa.sa_handler = sigsegv_handler;
|
sa.sa_handler = sigsegv_handler;
|
||||||
sa.sa_flags = SA_SIGINFO;
|
sa.sa_flags = SA_SIGINFO;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sigaction(SIGSEGV, &sa, NULL);
|
sigaction(SIGSEGV, &sa, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* signal(xyz);
|
* signal(xyz);
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,175 +1,175 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
// PatchEngine
|
// PatchEngine
|
||||||
// Supports simple memory patches, and has a partial Action Replay implementation
|
// Supports simple memory patches, and has a partial Action Replay implementation
|
||||||
// in ActionReplay.cpp/h.
|
// in ActionReplay.cpp/h.
|
||||||
|
|
||||||
// Zelda item hang fixes:
|
// Zelda item hang fixes:
|
||||||
// [Tue Aug 21 2007] [18:30:40] <Knuckles-> 0x802904b4 in US released
|
// [Tue Aug 21 2007] [18:30:40] <Knuckles-> 0x802904b4 in US released
|
||||||
// [Tue Aug 21 2007] [18:30:53] <Knuckles-> 0x80294d54 in EUR Demo version
|
// [Tue Aug 21 2007] [18:30:53] <Knuckles-> 0x80294d54 in EUR Demo version
|
||||||
// [Tue Aug 21 2007] [18:31:10] <Knuckles-> we just patch a blr on it (0x4E800020)
|
// [Tue Aug 21 2007] [18:31:10] <Knuckles-> we just patch a blr on it (0x4E800020)
|
||||||
// [OnLoad]
|
// [OnLoad]
|
||||||
// 0x80020394=dword,0x4e800020
|
// 0x80020394=dword,0x4e800020
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "PatchEngine.h"
|
#include "PatchEngine.h"
|
||||||
#include "HW/Memmap.h"
|
#include "HW/Memmap.h"
|
||||||
#include "ActionReplay.h"
|
#include "ActionReplay.h"
|
||||||
|
|
||||||
using namespace Common;
|
using namespace Common;
|
||||||
|
|
||||||
namespace PatchEngine
|
namespace PatchEngine
|
||||||
{
|
{
|
||||||
|
|
||||||
std::vector<Patch> onFrame;
|
std::vector<Patch> onFrame;
|
||||||
std::map<u32, int> speedHacks;
|
std::map<u32, int> speedHacks;
|
||||||
|
|
||||||
void LoadPatchSection(const char *section, std::vector<Patch> &patches, IniFile &ini)
|
void LoadPatchSection(const char *section, std::vector<Patch> &patches, IniFile &ini)
|
||||||
{
|
{
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
if (!ini.GetLines(section, lines))
|
if (!ini.GetLines(section, lines))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Patch currentPatch;
|
Patch currentPatch;
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
|
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
|
||||||
{
|
{
|
||||||
std::string line = *iter;
|
std::string line = *iter;
|
||||||
if (line.size())
|
if (line.size())
|
||||||
{
|
{
|
||||||
if (line[0] == '+' || line[0] == '$')
|
if (line[0] == '+' || line[0] == '$')
|
||||||
{
|
{
|
||||||
// Take care of the previous code
|
// Take care of the previous code
|
||||||
if (currentPatch.name.size()) patches.push_back(currentPatch);
|
if (currentPatch.name.size()) patches.push_back(currentPatch);
|
||||||
currentPatch.entries.clear();
|
currentPatch.entries.clear();
|
||||||
|
|
||||||
// Set active and name
|
// Set active and name
|
||||||
currentPatch.active = (line[0] == '+') ? true : false;
|
currentPatch.active = (line[0] == '+') ? true : false;
|
||||||
if (currentPatch.active)
|
if (currentPatch.active)
|
||||||
currentPatch.name = line.substr(2, line.size() - 2);
|
currentPatch.name = line.substr(2, line.size() - 2);
|
||||||
else
|
else
|
||||||
currentPatch.name = line.substr(1, line.size() - 1);
|
currentPatch.name = line.substr(1, line.size() - 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string::size_type loc = line.find_first_of('=', 0);
|
std::string::size_type loc = line.find_first_of('=', 0);
|
||||||
if (loc != std::string::npos)
|
if (loc != std::string::npos)
|
||||||
line.at(loc) = ':';
|
line.at(loc) = ':';
|
||||||
|
|
||||||
std::vector<std::string> items;
|
std::vector<std::string> items;
|
||||||
SplitString(line, ":", items);
|
SplitString(line, ":", items);
|
||||||
if (items.size() >= 3) {
|
if (items.size() >= 3) {
|
||||||
PatchEntry pE;
|
PatchEntry pE;
|
||||||
bool success = true;
|
bool success = true;
|
||||||
success = success && TryParseUInt(items[0], &pE.address);
|
success = success && TryParseUInt(items[0], &pE.address);
|
||||||
success = success && TryParseUInt(items[2], &pE.value);
|
success = success && TryParseUInt(items[2], &pE.value);
|
||||||
pE.type = (PatchType)ChooseStringFrom(items[1].c_str(), PatchTypeStrings);
|
pE.type = (PatchType)ChooseStringFrom(items[1].c_str(), PatchTypeStrings);
|
||||||
success = success && (pE.type != (PatchType)-1);
|
success = success && (pE.type != (PatchType)-1);
|
||||||
if (success)
|
if (success)
|
||||||
currentPatch.entries.push_back(pE);
|
currentPatch.entries.push_back(pE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (currentPatch.name.size()) patches.push_back(currentPatch);
|
if (currentPatch.name.size()) patches.push_back(currentPatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadSpeedhacks(const char *section, std::map<u32, int> &hacks, IniFile &ini) {
|
static void LoadSpeedhacks(const char *section, std::map<u32, int> &hacks, IniFile &ini) {
|
||||||
std::vector<std::string> keys;
|
std::vector<std::string> keys;
|
||||||
ini.GetKeys(section, keys);
|
ini.GetKeys(section, keys);
|
||||||
for (std::vector<std::string>::const_iterator iter = keys.begin(); iter != keys.end(); ++iter)
|
for (std::vector<std::string>::const_iterator iter = keys.begin(); iter != keys.end(); ++iter)
|
||||||
{
|
{
|
||||||
std::string key = *iter;
|
std::string key = *iter;
|
||||||
std::string value;
|
std::string value;
|
||||||
ini.Get(section, key.c_str(), &value, "BOGUS");
|
ini.Get(section, key.c_str(), &value, "BOGUS");
|
||||||
if (value != "BOGUS")
|
if (value != "BOGUS")
|
||||||
{
|
{
|
||||||
u32 address;
|
u32 address;
|
||||||
u32 cycles;
|
u32 cycles;
|
||||||
bool success = true;
|
bool success = true;
|
||||||
success = success && TryParseUInt(std::string(key.c_str()), &address);
|
success = success && TryParseUInt(std::string(key.c_str()), &address);
|
||||||
success = success && TryParseUInt(value, &cycles);
|
success = success && TryParseUInt(value, &cycles);
|
||||||
if (success) {
|
if (success) {
|
||||||
speedHacks[address] = (int)cycles;
|
speedHacks[address] = (int)cycles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetSpeedhackCycles(u32 addr)
|
int GetSpeedhackCycles(u32 addr)
|
||||||
{
|
{
|
||||||
std::map<u32, int>::const_iterator iter = speedHacks.find(addr);
|
std::map<u32, int>::const_iterator iter = speedHacks.find(addr);
|
||||||
if (iter == speedHacks.end())
|
if (iter == speedHacks.end())
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadPatches(const char *gameID)
|
void LoadPatches(const char *gameID)
|
||||||
{
|
{
|
||||||
IniFile ini;
|
IniFile ini;
|
||||||
std::string filename = std::string(FULL_GAMECONFIG_DIR) + gameID + ".ini";
|
std::string filename = std::string(FULL_GAMECONFIG_DIR) + gameID + ".ini";
|
||||||
if (ini.Load(filename.c_str())) {
|
if (ini.Load(filename.c_str())) {
|
||||||
LoadPatchSection("OnFrame", onFrame, ini);
|
LoadPatchSection("OnFrame", onFrame, ini);
|
||||||
LoadActionReplayCodes(ini);
|
LoadActionReplayCodes(ini);
|
||||||
LoadSpeedhacks("Speedhacks", speedHacks, ini);
|
LoadSpeedhacks("Speedhacks", speedHacks, ini);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyPatches(const std::vector<Patch> &patches)
|
void ApplyPatches(const std::vector<Patch> &patches)
|
||||||
{
|
{
|
||||||
for (std::vector<Patch>::const_iterator iter = patches.begin(); iter != patches.end(); ++iter)
|
for (std::vector<Patch>::const_iterator iter = patches.begin(); iter != patches.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (iter->active)
|
if (iter->active)
|
||||||
{
|
{
|
||||||
for (std::vector<PatchEntry>::const_iterator iter2 = iter->entries.begin(); iter2 != iter->entries.end(); ++iter2)
|
for (std::vector<PatchEntry>::const_iterator iter2 = iter->entries.begin(); iter2 != iter->entries.end(); ++iter2)
|
||||||
{
|
{
|
||||||
u32 addr = iter2->address;
|
u32 addr = iter2->address;
|
||||||
u32 value = iter2->value;
|
u32 value = iter2->value;
|
||||||
switch (iter2->type)
|
switch (iter2->type)
|
||||||
{
|
{
|
||||||
case PATCH_8BIT:
|
case PATCH_8BIT:
|
||||||
Memory::Write_U8((u8)value, addr);
|
Memory::Write_U8((u8)value, addr);
|
||||||
break;
|
break;
|
||||||
case PATCH_16BIT:
|
case PATCH_16BIT:
|
||||||
Memory::Write_U16((u16)value, addr);
|
Memory::Write_U16((u16)value, addr);
|
||||||
break;
|
break;
|
||||||
case PATCH_32BIT:
|
case PATCH_32BIT:
|
||||||
Memory::Write_U32(value, addr);
|
Memory::Write_U32(value, addr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
//unknown patchtype
|
//unknown patchtype
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyFramePatches()
|
void ApplyFramePatches()
|
||||||
{
|
{
|
||||||
ApplyPatches(onFrame);
|
ApplyPatches(onFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyARPatches()
|
void ApplyARPatches()
|
||||||
{
|
{
|
||||||
ActionReplayRunAllActive();
|
ActionReplayRunAllActive();
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,129 +1,129 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "DynamicLibrary.h"
|
#include "DynamicLibrary.h"
|
||||||
#include "Plugin_DSP.h"
|
#include "Plugin_DSP.h"
|
||||||
|
|
||||||
namespace PluginDSP
|
namespace PluginDSP
|
||||||
{
|
{
|
||||||
|
|
||||||
// Function Pointer
|
// Function Pointer
|
||||||
TGetDllInfo GetDllInfo = 0;
|
TGetDllInfo GetDllInfo = 0;
|
||||||
TDllConfig DllConfig = 0;
|
TDllConfig DllConfig = 0;
|
||||||
TDllDebugger DllDebugger = 0;
|
TDllDebugger DllDebugger = 0;
|
||||||
TDSP_Initialize DSP_Initialize = 0;
|
TDSP_Initialize DSP_Initialize = 0;
|
||||||
TDSP_Shutdown DSP_Shutdown = 0;
|
TDSP_Shutdown DSP_Shutdown = 0;
|
||||||
TDSP_ReadMailBox DSP_ReadMailboxHigh = 0;
|
TDSP_ReadMailBox DSP_ReadMailboxHigh = 0;
|
||||||
TDSP_ReadMailBox DSP_ReadMailboxLow = 0;
|
TDSP_ReadMailBox DSP_ReadMailboxLow = 0;
|
||||||
TDSP_WriteMailBox DSP_WriteMailboxHigh = 0;
|
TDSP_WriteMailBox DSP_WriteMailboxHigh = 0;
|
||||||
TDSP_WriteMailBox DSP_WriteMailboxLow = 0;
|
TDSP_WriteMailBox DSP_WriteMailboxLow = 0;
|
||||||
TDSP_ReadControlRegister DSP_ReadControlRegister = 0;
|
TDSP_ReadControlRegister DSP_ReadControlRegister = 0;
|
||||||
TDSP_WriteControlRegister DSP_WriteControlRegister = 0;
|
TDSP_WriteControlRegister DSP_WriteControlRegister = 0;
|
||||||
TDSP_Update DSP_Update = 0;
|
TDSP_Update DSP_Update = 0;
|
||||||
TDSP_SendAIBuffer DSP_SendAIBuffer = 0;
|
TDSP_SendAIBuffer DSP_SendAIBuffer = 0;
|
||||||
TDSP_DoState DSP_DoState = 0;
|
TDSP_DoState DSP_DoState = 0;
|
||||||
|
|
||||||
//! Library Instance
|
//! Library Instance
|
||||||
DynamicLibrary plugin;
|
DynamicLibrary plugin;
|
||||||
|
|
||||||
bool IsLoaded()
|
bool IsLoaded()
|
||||||
{
|
{
|
||||||
return plugin.IsLoaded();
|
return plugin.IsLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debug(HWND _hwnd, bool Show)
|
void Debug(HWND _hwnd, bool Show)
|
||||||
{
|
{
|
||||||
DllDebugger(_hwnd, Show);
|
DllDebugger(_hwnd, Show);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnloadPlugin()
|
void UnloadPlugin()
|
||||||
{
|
{
|
||||||
plugin.Unload();
|
plugin.Unload();
|
||||||
|
|
||||||
// Set Functions to NULL
|
// Set Functions to NULL
|
||||||
GetDllInfo = 0;
|
GetDllInfo = 0;
|
||||||
DllConfig = 0;
|
DllConfig = 0;
|
||||||
DllDebugger = 0;
|
DllDebugger = 0;
|
||||||
DSP_Initialize = 0;
|
DSP_Initialize = 0;
|
||||||
DSP_Shutdown = 0;
|
DSP_Shutdown = 0;
|
||||||
DSP_ReadMailboxHigh = 0;
|
DSP_ReadMailboxHigh = 0;
|
||||||
DSP_ReadMailboxLow = 0;
|
DSP_ReadMailboxLow = 0;
|
||||||
DSP_WriteMailboxHigh = 0;
|
DSP_WriteMailboxHigh = 0;
|
||||||
DSP_WriteMailboxLow = 0;
|
DSP_WriteMailboxLow = 0;
|
||||||
DSP_ReadControlRegister = 0;
|
DSP_ReadControlRegister = 0;
|
||||||
DSP_WriteControlRegister = 0;
|
DSP_WriteControlRegister = 0;
|
||||||
DSP_Update = 0;
|
DSP_Update = 0;
|
||||||
DSP_SendAIBuffer = 0;
|
DSP_SendAIBuffer = 0;
|
||||||
DSP_DoState = 0;
|
DSP_DoState = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadPlugin(const char *_Filename)
|
bool LoadPlugin(const char *_Filename)
|
||||||
{
|
{
|
||||||
int ret = plugin.Load(_Filename); // we may have alredy loaded this to open the debugger
|
int ret = plugin.Load(_Filename); // we may have alredy loaded this to open the debugger
|
||||||
|
|
||||||
if (ret == 1)
|
if (ret == 1)
|
||||||
{
|
{
|
||||||
GetDllInfo = reinterpret_cast<TGetDllInfo> (plugin.Get("GetDllInfo"));
|
GetDllInfo = reinterpret_cast<TGetDllInfo> (plugin.Get("GetDllInfo"));
|
||||||
DllConfig = reinterpret_cast<TDllConfig> (plugin.Get("DllConfig"));
|
DllConfig = reinterpret_cast<TDllConfig> (plugin.Get("DllConfig"));
|
||||||
DllDebugger = reinterpret_cast<TDllDebugger> (plugin.Get("DllDebugger"));
|
DllDebugger = reinterpret_cast<TDllDebugger> (plugin.Get("DllDebugger"));
|
||||||
DSP_Initialize = reinterpret_cast<TDSP_Initialize> (plugin.Get("DSP_Initialize"));
|
DSP_Initialize = reinterpret_cast<TDSP_Initialize> (plugin.Get("DSP_Initialize"));
|
||||||
DSP_Shutdown = reinterpret_cast<TDSP_Shutdown> (plugin.Get("DSP_Shutdown"));
|
DSP_Shutdown = reinterpret_cast<TDSP_Shutdown> (plugin.Get("DSP_Shutdown"));
|
||||||
DSP_ReadMailboxHigh = reinterpret_cast<TDSP_ReadMailBox> (plugin.Get("DSP_ReadMailboxHigh"));
|
DSP_ReadMailboxHigh = reinterpret_cast<TDSP_ReadMailBox> (plugin.Get("DSP_ReadMailboxHigh"));
|
||||||
DSP_ReadMailboxLow = reinterpret_cast<TDSP_ReadMailBox> (plugin.Get("DSP_ReadMailboxLow"));
|
DSP_ReadMailboxLow = reinterpret_cast<TDSP_ReadMailBox> (plugin.Get("DSP_ReadMailboxLow"));
|
||||||
DSP_WriteMailboxHigh = reinterpret_cast<TDSP_WriteMailBox> (plugin.Get("DSP_WriteMailboxHigh"));
|
DSP_WriteMailboxHigh = reinterpret_cast<TDSP_WriteMailBox> (plugin.Get("DSP_WriteMailboxHigh"));
|
||||||
DSP_WriteMailboxLow = reinterpret_cast<TDSP_WriteMailBox> (plugin.Get("DSP_WriteMailboxLow"));
|
DSP_WriteMailboxLow = reinterpret_cast<TDSP_WriteMailBox> (plugin.Get("DSP_WriteMailboxLow"));
|
||||||
DSP_ReadControlRegister = reinterpret_cast<TDSP_ReadControlRegister> (plugin.Get("DSP_ReadControlRegister"));
|
DSP_ReadControlRegister = reinterpret_cast<TDSP_ReadControlRegister> (plugin.Get("DSP_ReadControlRegister"));
|
||||||
DSP_WriteControlRegister = reinterpret_cast<TDSP_WriteControlRegister> (plugin.Get("DSP_WriteControlRegister"));
|
DSP_WriteControlRegister = reinterpret_cast<TDSP_WriteControlRegister> (plugin.Get("DSP_WriteControlRegister"));
|
||||||
DSP_Update = reinterpret_cast<TDSP_Update> (plugin.Get("DSP_Update"));
|
DSP_Update = reinterpret_cast<TDSP_Update> (plugin.Get("DSP_Update"));
|
||||||
DSP_SendAIBuffer = reinterpret_cast<TDSP_SendAIBuffer> (plugin.Get("DSP_SendAIBuffer"));
|
DSP_SendAIBuffer = reinterpret_cast<TDSP_SendAIBuffer> (plugin.Get("DSP_SendAIBuffer"));
|
||||||
DSP_DoState = reinterpret_cast<TDSP_DoState> (plugin.Get("DSP_DoState"));
|
DSP_DoState = reinterpret_cast<TDSP_DoState> (plugin.Get("DSP_DoState"));
|
||||||
|
|
||||||
if ((GetDllInfo != 0) &&
|
if ((GetDllInfo != 0) &&
|
||||||
(DSP_Initialize != 0) &&
|
(DSP_Initialize != 0) &&
|
||||||
(DSP_Shutdown != 0) &&
|
(DSP_Shutdown != 0) &&
|
||||||
(DSP_ReadMailboxHigh != 0) &&
|
(DSP_ReadMailboxHigh != 0) &&
|
||||||
(DSP_ReadMailboxLow != 0) &&
|
(DSP_ReadMailboxLow != 0) &&
|
||||||
(DSP_WriteMailboxHigh != 0) &&
|
(DSP_WriteMailboxHigh != 0) &&
|
||||||
(DSP_WriteMailboxLow != 0) &&
|
(DSP_WriteMailboxLow != 0) &&
|
||||||
(DSP_ReadControlRegister != 0) &&
|
(DSP_ReadControlRegister != 0) &&
|
||||||
(DSP_WriteControlRegister != 0) &&
|
(DSP_WriteControlRegister != 0) &&
|
||||||
(DSP_Update != 0) &&
|
(DSP_Update != 0) &&
|
||||||
(DSP_SendAIBuffer != 0) &&
|
(DSP_SendAIBuffer != 0) &&
|
||||||
(DSP_DoState != 0))
|
(DSP_DoState != 0))
|
||||||
{
|
{
|
||||||
//PanicAlert("return true: %i", ret);
|
//PanicAlert("return true: %i", ret);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UnloadPlugin();
|
UnloadPlugin();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ret == 2)
|
else if (ret == 2)
|
||||||
{
|
{
|
||||||
//PanicAlert("return true: %i", ret);
|
//PanicAlert("return true: %i", ret);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (ret == 0)
|
else if (ret == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,163 +1,163 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Plugin_DVD.h"
|
#include "Plugin_DVD.h"
|
||||||
|
|
||||||
|
|
||||||
namespace PluginDVD
|
namespace PluginDVD
|
||||||
{
|
{
|
||||||
|
|
||||||
//! Function Types
|
//! Function Types
|
||||||
typedef void (__cdecl* TGetDllInfo) (PLUGIN_INFO*);
|
typedef void (__cdecl* TGetDllInfo) (PLUGIN_INFO*);
|
||||||
typedef void (__cdecl* TDllConfig) (HWND);
|
typedef void (__cdecl* TDllConfig) (HWND);
|
||||||
typedef void (__cdecl* TDVD_Initialize) (SDVDInitialize);
|
typedef void (__cdecl* TDVD_Initialize) (SDVDInitialize);
|
||||||
typedef void (__cdecl* TDVD_Shutdown) ();
|
typedef void (__cdecl* TDVD_Shutdown) ();
|
||||||
typedef void (__cdecl* TDVD_SetISOFile) (const char*);
|
typedef void (__cdecl* TDVD_SetISOFile) (const char*);
|
||||||
typedef BOOL (__cdecl* TDVD_GetISOName) (TCHAR*, int);
|
typedef BOOL (__cdecl* TDVD_GetISOName) (TCHAR*, int);
|
||||||
typedef BOOL (__cdecl* TDVD_ReadToPtr) (LPBYTE, u64, u64);
|
typedef BOOL (__cdecl* TDVD_ReadToPtr) (LPBYTE, u64, u64);
|
||||||
typedef BOOL (__cdecl* TDVD_IsValid) ();
|
typedef BOOL (__cdecl* TDVD_IsValid) ();
|
||||||
typedef u32 (__cdecl* TDVD_Read32) (u64);
|
typedef u32 (__cdecl* TDVD_Read32) (u64);
|
||||||
|
|
||||||
//! Function Pointer
|
//! Function Pointer
|
||||||
TGetDllInfo g_GetDllInfo = NULL;
|
TGetDllInfo g_GetDllInfo = NULL;
|
||||||
TDllConfig g_DllConfig = NULL;
|
TDllConfig g_DllConfig = NULL;
|
||||||
TDVD_Initialize g_DVD_Initialize = NULL;
|
TDVD_Initialize g_DVD_Initialize = NULL;
|
||||||
TDVD_Shutdown g_DVD_Shutdown = NULL;
|
TDVD_Shutdown g_DVD_Shutdown = NULL;
|
||||||
TDVD_SetISOFile g_DVD_SetISOFile = NULL;
|
TDVD_SetISOFile g_DVD_SetISOFile = NULL;
|
||||||
TDVD_GetISOName g_DVD_GetISOName = NULL;
|
TDVD_GetISOName g_DVD_GetISOName = NULL;
|
||||||
TDVD_ReadToPtr g_DVD_ReadToPtr = NULL;
|
TDVD_ReadToPtr g_DVD_ReadToPtr = NULL;
|
||||||
TDVD_Read32 g_DVD_Read32 = NULL;
|
TDVD_Read32 g_DVD_Read32 = NULL;
|
||||||
TDVD_IsValid g_DVD_IsValid = NULL;
|
TDVD_IsValid g_DVD_IsValid = NULL;
|
||||||
|
|
||||||
//! Library Instance
|
//! Library Instance
|
||||||
HINSTANCE g_hLibraryInstance = NULL;
|
HINSTANCE g_hLibraryInstance = NULL;
|
||||||
|
|
||||||
bool IsLoaded()
|
bool IsLoaded()
|
||||||
{
|
{
|
||||||
return (g_hLibraryInstance != NULL);
|
return (g_hLibraryInstance != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadPlugin(const char *_strFilename)
|
bool LoadPlugin(const char *_strFilename)
|
||||||
{
|
{
|
||||||
UnloadPlugin();
|
UnloadPlugin();
|
||||||
g_hLibraryInstance = LoadLibrary(_strFilename);
|
g_hLibraryInstance = LoadLibrary(_strFilename);
|
||||||
|
|
||||||
if (g_hLibraryInstance)
|
if (g_hLibraryInstance)
|
||||||
{
|
{
|
||||||
g_GetDllInfo = reinterpret_cast<TGetDllInfo> (GetProcAddress(g_hLibraryInstance, "GetDllInfo"));
|
g_GetDllInfo = reinterpret_cast<TGetDllInfo> (GetProcAddress(g_hLibraryInstance, "GetDllInfo"));
|
||||||
g_DllConfig = reinterpret_cast<TDllConfig> (GetProcAddress(g_hLibraryInstance, "DllConfig"));
|
g_DllConfig = reinterpret_cast<TDllConfig> (GetProcAddress(g_hLibraryInstance, "DllConfig"));
|
||||||
g_DVD_Initialize = reinterpret_cast<TDVD_Initialize> (GetProcAddress(g_hLibraryInstance, "DVD_Initialize"));
|
g_DVD_Initialize = reinterpret_cast<TDVD_Initialize> (GetProcAddress(g_hLibraryInstance, "DVD_Initialize"));
|
||||||
g_DVD_Shutdown = reinterpret_cast<TDVD_Shutdown> (GetProcAddress(g_hLibraryInstance, "DVD_Shutdown"));
|
g_DVD_Shutdown = reinterpret_cast<TDVD_Shutdown> (GetProcAddress(g_hLibraryInstance, "DVD_Shutdown"));
|
||||||
g_DVD_SetISOFile = reinterpret_cast<TDVD_SetISOFile> (GetProcAddress(g_hLibraryInstance, "DVD_SetISOFile"));
|
g_DVD_SetISOFile = reinterpret_cast<TDVD_SetISOFile> (GetProcAddress(g_hLibraryInstance, "DVD_SetISOFile"));
|
||||||
g_DVD_GetISOName = reinterpret_cast<TDVD_GetISOName> (GetProcAddress(g_hLibraryInstance, "DVD_GetISOName"));
|
g_DVD_GetISOName = reinterpret_cast<TDVD_GetISOName> (GetProcAddress(g_hLibraryInstance, "DVD_GetISOName"));
|
||||||
g_DVD_ReadToPtr = reinterpret_cast<TDVD_ReadToPtr> (GetProcAddress(g_hLibraryInstance, "DVD_ReadToPtr"));
|
g_DVD_ReadToPtr = reinterpret_cast<TDVD_ReadToPtr> (GetProcAddress(g_hLibraryInstance, "DVD_ReadToPtr"));
|
||||||
g_DVD_Read32 = reinterpret_cast<TDVD_Read32> (GetProcAddress(g_hLibraryInstance, "DVD_Read32"));
|
g_DVD_Read32 = reinterpret_cast<TDVD_Read32> (GetProcAddress(g_hLibraryInstance, "DVD_Read32"));
|
||||||
g_DVD_IsValid = reinterpret_cast<TDVD_IsValid> (GetProcAddress(g_hLibraryInstance, "DVD_IsValid"));
|
g_DVD_IsValid = reinterpret_cast<TDVD_IsValid> (GetProcAddress(g_hLibraryInstance, "DVD_IsValid"));
|
||||||
|
|
||||||
if ((g_GetDllInfo != NULL) &&
|
if ((g_GetDllInfo != NULL) &&
|
||||||
(g_DllConfig != NULL) &&
|
(g_DllConfig != NULL) &&
|
||||||
(g_DVD_Initialize != NULL) &&
|
(g_DVD_Initialize != NULL) &&
|
||||||
(g_DVD_Shutdown != NULL) &&
|
(g_DVD_Shutdown != NULL) &&
|
||||||
(g_DVD_SetISOFile != NULL) &&
|
(g_DVD_SetISOFile != NULL) &&
|
||||||
(g_DVD_GetISOName != NULL) &&
|
(g_DVD_GetISOName != NULL) &&
|
||||||
(g_DVD_ReadToPtr != NULL) &&
|
(g_DVD_ReadToPtr != NULL) &&
|
||||||
(g_DVD_IsValid != NULL) &&
|
(g_DVD_IsValid != NULL) &&
|
||||||
(g_DVD_Read32 != NULL))
|
(g_DVD_Read32 != NULL))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UnloadPlugin();
|
UnloadPlugin();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnloadPlugin()
|
void UnloadPlugin()
|
||||||
{
|
{
|
||||||
// Set Functions to NULL
|
// Set Functions to NULL
|
||||||
g_GetDllInfo = NULL;
|
g_GetDllInfo = NULL;
|
||||||
g_DllConfig = NULL;
|
g_DllConfig = NULL;
|
||||||
g_DVD_Initialize = NULL;
|
g_DVD_Initialize = NULL;
|
||||||
g_DVD_Shutdown = NULL;
|
g_DVD_Shutdown = NULL;
|
||||||
g_DVD_SetISOFile = NULL;
|
g_DVD_SetISOFile = NULL;
|
||||||
g_DVD_Read32 = NULL;
|
g_DVD_Read32 = NULL;
|
||||||
g_DVD_ReadToPtr = NULL;
|
g_DVD_ReadToPtr = NULL;
|
||||||
g_DVD_IsValid = NULL;
|
g_DVD_IsValid = NULL;
|
||||||
|
|
||||||
// Unload library
|
// Unload library
|
||||||
if (g_hLibraryInstance != NULL)
|
if (g_hLibraryInstance != NULL)
|
||||||
{
|
{
|
||||||
FreeLibrary(g_hLibraryInstance);
|
FreeLibrary(g_hLibraryInstance);
|
||||||
g_hLibraryInstance = NULL;
|
g_hLibraryInstance = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// --- Plugin Functions ---
|
// --- Plugin Functions ---
|
||||||
//
|
//
|
||||||
|
|
||||||
void GetDllInfo(PLUGIN_INFO* _PluginInfo)
|
void GetDllInfo(PLUGIN_INFO* _PluginInfo)
|
||||||
{
|
{
|
||||||
g_GetDllInfo(_PluginInfo);
|
g_GetDllInfo(_PluginInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DllConfig(HWND _hParent)
|
void DllConfig(HWND _hParent)
|
||||||
{
|
{
|
||||||
g_DllConfig(_hParent);
|
g_DllConfig(_hParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DVD_Initialize(SDVDInitialize _DVDInitialize)
|
void DVD_Initialize(SDVDInitialize _DVDInitialize)
|
||||||
{
|
{
|
||||||
g_DVD_Initialize(_DVDInitialize);
|
g_DVD_Initialize(_DVDInitialize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DVD_Shutdown()
|
void DVD_Shutdown()
|
||||||
{
|
{
|
||||||
g_DVD_Shutdown();
|
g_DVD_Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DVD_ReadToPtr(LPBYTE ptr, u64 _dwOffset, u64 _dwLength)
|
bool DVD_ReadToPtr(LPBYTE ptr, u64 _dwOffset, u64 _dwLength)
|
||||||
{
|
{
|
||||||
return (g_DVD_ReadToPtr(ptr, _dwOffset, _dwLength) == TRUE) ? true : false;
|
return (g_DVD_ReadToPtr(ptr, _dwOffset, _dwLength) == TRUE) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DVD_IsValid()
|
bool DVD_IsValid()
|
||||||
{
|
{
|
||||||
return (g_DVD_IsValid() == TRUE) ? true : false;
|
return (g_DVD_IsValid() == TRUE) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 DVD_Read32(u64 _dwOffset)
|
u32 DVD_Read32(u64 _dwOffset)
|
||||||
{
|
{
|
||||||
return g_DVD_Read32(_dwOffset);
|
return g_DVD_Read32(_dwOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DVD_SetISOFile(const char* _szFilename)
|
void DVD_SetISOFile(const char* _szFilename)
|
||||||
{
|
{
|
||||||
g_DVD_SetISOFile(_szFilename);
|
g_DVD_SetISOFile(_szFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL DVD_GetISOName(TCHAR * _szFilename, int maxlen)
|
BOOL DVD_GetISOName(TCHAR * _szFilename, int maxlen)
|
||||||
{
|
{
|
||||||
return g_DVD_GetISOName(_szFilename, maxlen);
|
return g_DVD_GetISOName(_szFilename, maxlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace PluginDVD
|
} // end of namespace PluginDVD
|
|
@ -1,83 +1,83 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "DynamicLibrary.h"
|
#include "DynamicLibrary.h"
|
||||||
#include "Plugin_PAD.h"
|
#include "Plugin_PAD.h"
|
||||||
|
|
||||||
namespace PluginPAD
|
namespace PluginPAD
|
||||||
{
|
{
|
||||||
|
|
||||||
// Function Pointers
|
// Function Pointers
|
||||||
TGetDllInfo GetDllInfo = 0;
|
TGetDllInfo GetDllInfo = 0;
|
||||||
TPAD_Shutdown PAD_Shutdown = 0;
|
TPAD_Shutdown PAD_Shutdown = 0;
|
||||||
TDllConfig DllConfig = 0;
|
TDllConfig DllConfig = 0;
|
||||||
TPAD_Initialize PAD_Initialize = 0;
|
TPAD_Initialize PAD_Initialize = 0;
|
||||||
TPAD_GetStatus PAD_GetStatus = 0;
|
TPAD_GetStatus PAD_GetStatus = 0;
|
||||||
TPAD_Rumble PAD_Rumble = 0;
|
TPAD_Rumble PAD_Rumble = 0;
|
||||||
TPAD_GetAttachedPads PAD_GetAttachedPads = 0;
|
TPAD_GetAttachedPads PAD_GetAttachedPads = 0;
|
||||||
|
|
||||||
// Library Instance
|
// Library Instance
|
||||||
DynamicLibrary plugin;
|
DynamicLibrary plugin;
|
||||||
|
|
||||||
bool IsLoaded()
|
bool IsLoaded()
|
||||||
{
|
{
|
||||||
return plugin.IsLoaded();
|
return plugin.IsLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnloadPlugin()
|
void UnloadPlugin()
|
||||||
{
|
{
|
||||||
plugin.Unload();
|
plugin.Unload();
|
||||||
// Set Functions to 0
|
// Set Functions to 0
|
||||||
GetDllInfo = 0;
|
GetDllInfo = 0;
|
||||||
PAD_Shutdown = 0;
|
PAD_Shutdown = 0;
|
||||||
DllConfig = 0;
|
DllConfig = 0;
|
||||||
PAD_Initialize = 0;
|
PAD_Initialize = 0;
|
||||||
PAD_GetStatus = 0;
|
PAD_GetStatus = 0;
|
||||||
PAD_Rumble = 0;
|
PAD_Rumble = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadPlugin(const char *_Filename)
|
bool LoadPlugin(const char *_Filename)
|
||||||
{
|
{
|
||||||
if (plugin.Load(_Filename))
|
if (plugin.Load(_Filename))
|
||||||
{
|
{
|
||||||
GetDllInfo = reinterpret_cast<TGetDllInfo> (plugin.Get("GetDllInfo"));
|
GetDllInfo = reinterpret_cast<TGetDllInfo> (plugin.Get("GetDllInfo"));
|
||||||
DllConfig = reinterpret_cast<TDllConfig> (plugin.Get("DllConfig"));
|
DllConfig = reinterpret_cast<TDllConfig> (plugin.Get("DllConfig"));
|
||||||
PAD_Initialize = reinterpret_cast<TPAD_Initialize> (plugin.Get("PAD_Initialize"));
|
PAD_Initialize = reinterpret_cast<TPAD_Initialize> (plugin.Get("PAD_Initialize"));
|
||||||
PAD_Shutdown = reinterpret_cast<TPAD_Shutdown> (plugin.Get("PAD_Shutdown"));
|
PAD_Shutdown = reinterpret_cast<TPAD_Shutdown> (plugin.Get("PAD_Shutdown"));
|
||||||
PAD_GetStatus = reinterpret_cast<TPAD_GetStatus> (plugin.Get("PAD_GetStatus"));
|
PAD_GetStatus = reinterpret_cast<TPAD_GetStatus> (plugin.Get("PAD_GetStatus"));
|
||||||
PAD_Rumble = reinterpret_cast<TPAD_Rumble> (plugin.Get("PAD_Rumble"));
|
PAD_Rumble = reinterpret_cast<TPAD_Rumble> (plugin.Get("PAD_Rumble"));
|
||||||
PAD_GetAttachedPads = reinterpret_cast<TPAD_GetAttachedPads>(plugin.Get("PAD_GetAttachedPads"));
|
PAD_GetAttachedPads = reinterpret_cast<TPAD_GetAttachedPads>(plugin.Get("PAD_GetAttachedPads"));
|
||||||
|
|
||||||
if ((GetDllInfo != 0) &&
|
if ((GetDllInfo != 0) &&
|
||||||
(DllConfig != 0) &&
|
(DllConfig != 0) &&
|
||||||
(PAD_Initialize != 0) &&
|
(PAD_Initialize != 0) &&
|
||||||
(PAD_Shutdown != 0) &&
|
(PAD_Shutdown != 0) &&
|
||||||
(PAD_GetStatus != 0))
|
(PAD_GetStatus != 0))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UnloadPlugin();
|
UnloadPlugin();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace PluginPAD
|
} // end of namespace PluginPAD
|
||||||
|
|
|
@ -1,143 +1,143 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "DynamicLibrary.h"
|
#include "DynamicLibrary.h"
|
||||||
#include "Plugin_Video.h"
|
#include "Plugin_Video.h"
|
||||||
#include "Plugin.h"
|
#include "Plugin.h"
|
||||||
|
|
||||||
extern DynamicLibrary Common::CPlugin;
|
extern DynamicLibrary Common::CPlugin;
|
||||||
|
|
||||||
namespace PluginVideo
|
namespace PluginVideo
|
||||||
{
|
{
|
||||||
|
|
||||||
// Function Pointer
|
// Function Pointer
|
||||||
TGetDllInfo GetDllInfo = 0;
|
TGetDllInfo GetDllInfo = 0;
|
||||||
TDllConfig DllConfig = 0;
|
TDllConfig DllConfig = 0;
|
||||||
TDllDebugger DllDebugger = 0;
|
TDllDebugger DllDebugger = 0;
|
||||||
TVideo_Initialize Video_Initialize = 0;
|
TVideo_Initialize Video_Initialize = 0;
|
||||||
TVideo_Prepare Video_Prepare = 0;
|
TVideo_Prepare Video_Prepare = 0;
|
||||||
TVideo_Shutdown Video_Shutdown = 0;
|
TVideo_Shutdown Video_Shutdown = 0;
|
||||||
TVideo_SendFifoData Video_SendFifoData = 0;
|
TVideo_SendFifoData Video_SendFifoData = 0;
|
||||||
TVideo_UpdateXFB Video_UpdateXFB = 0;
|
TVideo_UpdateXFB Video_UpdateXFB = 0;
|
||||||
TVideo_Screenshot Video_Screenshot = 0;
|
TVideo_Screenshot Video_Screenshot = 0;
|
||||||
TVideo_EnterLoop Video_EnterLoop = 0;
|
TVideo_EnterLoop Video_EnterLoop = 0;
|
||||||
TVideo_AddMessage Video_AddMessage = 0;
|
TVideo_AddMessage Video_AddMessage = 0;
|
||||||
TVideo_DoState Video_DoState = 0;
|
TVideo_DoState Video_DoState = 0;
|
||||||
TVideo_Stop Video_Stop = 0;
|
TVideo_Stop Video_Stop = 0;
|
||||||
|
|
||||||
// Library Instance
|
// Library Instance
|
||||||
DynamicLibrary plugin;
|
DynamicLibrary plugin;
|
||||||
|
|
||||||
void Debug(HWND _hwnd, bool Show)
|
void Debug(HWND _hwnd, bool Show)
|
||||||
{
|
{
|
||||||
DllDebugger(_hwnd, Show);
|
DllDebugger(_hwnd, Show);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsLoaded()
|
bool IsLoaded()
|
||||||
{
|
{
|
||||||
return plugin.IsLoaded();
|
return plugin.IsLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnloadPlugin()
|
void UnloadPlugin()
|
||||||
{
|
{
|
||||||
//PanicAlert("Video UnloadPlugin");
|
//PanicAlert("Video UnloadPlugin");
|
||||||
|
|
||||||
// set Functions to 0
|
// set Functions to 0
|
||||||
GetDllInfo = 0;
|
GetDllInfo = 0;
|
||||||
DllConfig = 0;
|
DllConfig = 0;
|
||||||
DllDebugger = 0;
|
DllDebugger = 0;
|
||||||
Video_Initialize = 0;
|
Video_Initialize = 0;
|
||||||
Video_Prepare = 0;
|
Video_Prepare = 0;
|
||||||
Video_Shutdown = 0;
|
Video_Shutdown = 0;
|
||||||
Video_SendFifoData = 0;
|
Video_SendFifoData = 0;
|
||||||
Video_UpdateXFB = 0;
|
Video_UpdateXFB = 0;
|
||||||
Video_AddMessage = 0;
|
Video_AddMessage = 0;
|
||||||
Video_DoState = 0;
|
Video_DoState = 0;
|
||||||
Video_Stop = 0;
|
Video_Stop = 0;
|
||||||
|
|
||||||
plugin.Unload();
|
plugin.Unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==============================================
|
// ==============================================
|
||||||
/* Load the plugin, but first check if we have already loaded the plugin for
|
/* Load the plugin, but first check if we have already loaded the plugin for
|
||||||
the sake of showing the debugger.
|
the sake of showing the debugger.
|
||||||
|
|
||||||
ret values:
|
ret values:
|
||||||
0 = failed
|
0 = failed
|
||||||
1 = loaded successfully
|
1 = loaded successfully
|
||||||
2 = already loaded from PluginManager.cpp, use it as it is */
|
2 = already loaded from PluginManager.cpp, use it as it is */
|
||||||
// ------------
|
// ------------
|
||||||
bool LoadPlugin(const char *_Filename)
|
bool LoadPlugin(const char *_Filename)
|
||||||
{
|
{
|
||||||
int ret = plugin.Load(_Filename);
|
int ret = plugin.Load(_Filename);
|
||||||
|
|
||||||
if (ret == 1)
|
if (ret == 1)
|
||||||
{
|
{
|
||||||
GetDllInfo = reinterpret_cast<TGetDllInfo> (plugin.Get("GetDllInfo"));
|
GetDllInfo = reinterpret_cast<TGetDllInfo> (plugin.Get("GetDllInfo"));
|
||||||
DllConfig = reinterpret_cast<TDllConfig> (plugin.Get("DllConfig"));
|
DllConfig = reinterpret_cast<TDllConfig> (plugin.Get("DllConfig"));
|
||||||
DllDebugger = reinterpret_cast<TDllDebugger> (plugin.Get("DllDebugger"));
|
DllDebugger = reinterpret_cast<TDllDebugger> (plugin.Get("DllDebugger"));
|
||||||
Video_Initialize = reinterpret_cast<TVideo_Initialize> (plugin.Get("Video_Initialize"));
|
Video_Initialize = reinterpret_cast<TVideo_Initialize> (plugin.Get("Video_Initialize"));
|
||||||
Video_Prepare = reinterpret_cast<TVideo_Prepare> (plugin.Get("Video_Prepare"));
|
Video_Prepare = reinterpret_cast<TVideo_Prepare> (plugin.Get("Video_Prepare"));
|
||||||
Video_Shutdown = reinterpret_cast<TVideo_Shutdown> (plugin.Get("Video_Shutdown"));
|
Video_Shutdown = reinterpret_cast<TVideo_Shutdown> (plugin.Get("Video_Shutdown"));
|
||||||
Video_SendFifoData = reinterpret_cast<TVideo_SendFifoData> (plugin.Get("Video_SendFifoData"));
|
Video_SendFifoData = reinterpret_cast<TVideo_SendFifoData> (plugin.Get("Video_SendFifoData"));
|
||||||
Video_UpdateXFB = reinterpret_cast<TVideo_UpdateXFB> (plugin.Get("Video_UpdateXFB"));
|
Video_UpdateXFB = reinterpret_cast<TVideo_UpdateXFB> (plugin.Get("Video_UpdateXFB"));
|
||||||
Video_Screenshot = reinterpret_cast<TVideo_Screenshot> (plugin.Get("Video_Screenshot"));
|
Video_Screenshot = reinterpret_cast<TVideo_Screenshot> (plugin.Get("Video_Screenshot"));
|
||||||
Video_EnterLoop = reinterpret_cast<TVideo_EnterLoop> (plugin.Get("Video_EnterLoop"));
|
Video_EnterLoop = reinterpret_cast<TVideo_EnterLoop> (plugin.Get("Video_EnterLoop"));
|
||||||
Video_AddMessage = reinterpret_cast<TVideo_AddMessage> (plugin.Get("Video_AddMessage"));
|
Video_AddMessage = reinterpret_cast<TVideo_AddMessage> (plugin.Get("Video_AddMessage"));
|
||||||
Video_DoState = reinterpret_cast<TVideo_DoState> (plugin.Get("Video_DoState"));
|
Video_DoState = reinterpret_cast<TVideo_DoState> (plugin.Get("Video_DoState"));
|
||||||
Video_Stop = reinterpret_cast<TVideo_Stop> (plugin.Get("Video_Stop"));
|
Video_Stop = reinterpret_cast<TVideo_Stop> (plugin.Get("Video_Stop"));
|
||||||
if ((GetDllInfo != 0) &&
|
if ((GetDllInfo != 0) &&
|
||||||
(DllConfig != 0) &&
|
(DllConfig != 0) &&
|
||||||
(DllDebugger != 0) &&
|
(DllDebugger != 0) &&
|
||||||
(Video_Initialize != 0) &&
|
(Video_Initialize != 0) &&
|
||||||
(Video_Prepare != 0) &&
|
(Video_Prepare != 0) &&
|
||||||
(Video_Shutdown != 0) &&
|
(Video_Shutdown != 0) &&
|
||||||
(Video_SendFifoData != 0) &&
|
(Video_SendFifoData != 0) &&
|
||||||
(Video_UpdateXFB != 0) &&
|
(Video_UpdateXFB != 0) &&
|
||||||
(Video_EnterLoop != 0) &&
|
(Video_EnterLoop != 0) &&
|
||||||
(Video_Screenshot != 0) &&
|
(Video_Screenshot != 0) &&
|
||||||
(Video_AddMessage != 0) &&
|
(Video_AddMessage != 0) &&
|
||||||
(Video_DoState != 0) &&
|
(Video_DoState != 0) &&
|
||||||
(Video_Stop != 0))
|
(Video_Stop != 0))
|
||||||
{
|
{
|
||||||
//PanicAlert("return true: %i", ret);
|
//PanicAlert("return true: %i", ret);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UnloadPlugin();
|
UnloadPlugin();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(ret == 2)
|
else if(ret == 2)
|
||||||
{
|
{
|
||||||
//PanicAlert("return true: %i", ret);
|
//PanicAlert("return true: %i", ret);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(ret == 0)
|
else if(ret == 0)
|
||||||
{
|
{
|
||||||
//PanicAlert("return false: %i", ret);
|
//PanicAlert("return false: %i", ret);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// ============
|
// ============
|
||||||
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,105 +1,105 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "DynamicLibrary.h"
|
#include "DynamicLibrary.h"
|
||||||
#include "Plugin_Wiimote.h"
|
#include "Plugin_Wiimote.h"
|
||||||
|
|
||||||
namespace PluginWiimote
|
namespace PluginWiimote
|
||||||
{
|
{
|
||||||
|
|
||||||
// Function Pointer
|
// Function Pointer
|
||||||
TGetDllInfo GetDllInfo = 0;
|
TGetDllInfo GetDllInfo = 0;
|
||||||
TDllConfig DllConfig = 0;
|
TDllConfig DllConfig = 0;
|
||||||
TWiimote_Initialize Wiimote_Initialize = 0;
|
TWiimote_Initialize Wiimote_Initialize = 0;
|
||||||
TWiimote_Shutdown Wiimote_Shutdown = 0;
|
TWiimote_Shutdown Wiimote_Shutdown = 0;
|
||||||
TWiimote_Output Wiimote_ControlChannel = 0;
|
TWiimote_Output Wiimote_ControlChannel = 0;
|
||||||
TWiimote_Input Wiimote_InterruptChannel = 0;
|
TWiimote_Input Wiimote_InterruptChannel = 0;
|
||||||
TWiimote_Update Wiimote_Update = 0;
|
TWiimote_Update Wiimote_Update = 0;
|
||||||
TWiimote_GetAttachedControllers Wiimote_GetAttachedControllers = 0;
|
TWiimote_GetAttachedControllers Wiimote_GetAttachedControllers = 0;
|
||||||
TWiimote_DoState Wiimote_DoState = 0;
|
TWiimote_DoState Wiimote_DoState = 0;
|
||||||
|
|
||||||
//! Library Instance
|
//! Library Instance
|
||||||
DynamicLibrary plugin;
|
DynamicLibrary plugin;
|
||||||
|
|
||||||
bool IsLoaded()
|
bool IsLoaded()
|
||||||
{
|
{
|
||||||
return plugin.IsLoaded();
|
return plugin.IsLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnloadPlugin()
|
void UnloadPlugin()
|
||||||
{
|
{
|
||||||
plugin.Unload();
|
plugin.Unload();
|
||||||
|
|
||||||
// Set Functions to NULL
|
// Set Functions to NULL
|
||||||
GetDllInfo = 0;
|
GetDllInfo = 0;
|
||||||
DllConfig = 0;
|
DllConfig = 0;
|
||||||
Wiimote_Initialize = 0;
|
Wiimote_Initialize = 0;
|
||||||
Wiimote_Shutdown = 0;
|
Wiimote_Shutdown = 0;
|
||||||
Wiimote_ControlChannel = 0;
|
Wiimote_ControlChannel = 0;
|
||||||
Wiimote_InterruptChannel = 0;
|
Wiimote_InterruptChannel = 0;
|
||||||
Wiimote_Update = 0;
|
Wiimote_Update = 0;
|
||||||
Wiimote_GetAttachedControllers = 0;
|
Wiimote_GetAttachedControllers = 0;
|
||||||
Wiimote_DoState = 0;
|
Wiimote_DoState = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadPlugin(const char *_Filename)
|
bool LoadPlugin(const char *_Filename)
|
||||||
{
|
{
|
||||||
if (plugin.Load(_Filename))
|
if (plugin.Load(_Filename))
|
||||||
{
|
{
|
||||||
LOG(MASTER_LOG, "getting Wiimote Plugin function pointers...");
|
LOG(MASTER_LOG, "getting Wiimote Plugin function pointers...");
|
||||||
GetDllInfo = reinterpret_cast<TGetDllInfo> (plugin.Get("GetDllInfo"));
|
GetDllInfo = reinterpret_cast<TGetDllInfo> (plugin.Get("GetDllInfo"));
|
||||||
DllConfig = reinterpret_cast<TDllConfig> (plugin.Get("DllConfig"));
|
DllConfig = reinterpret_cast<TDllConfig> (plugin.Get("DllConfig"));
|
||||||
Wiimote_Initialize = reinterpret_cast<TWiimote_Initialize> (plugin.Get("Wiimote_Initialize"));
|
Wiimote_Initialize = reinterpret_cast<TWiimote_Initialize> (plugin.Get("Wiimote_Initialize"));
|
||||||
Wiimote_Shutdown = reinterpret_cast<TWiimote_Shutdown> (plugin.Get("Wiimote_Shutdown"));
|
Wiimote_Shutdown = reinterpret_cast<TWiimote_Shutdown> (plugin.Get("Wiimote_Shutdown"));
|
||||||
Wiimote_ControlChannel = reinterpret_cast<TWiimote_Output> (plugin.Get("Wiimote_ControlChannel"));
|
Wiimote_ControlChannel = reinterpret_cast<TWiimote_Output> (plugin.Get("Wiimote_ControlChannel"));
|
||||||
Wiimote_InterruptChannel = reinterpret_cast<TWiimote_Input> (plugin.Get("Wiimote_InterruptChannel"));
|
Wiimote_InterruptChannel = reinterpret_cast<TWiimote_Input> (plugin.Get("Wiimote_InterruptChannel"));
|
||||||
Wiimote_Update = reinterpret_cast<TWiimote_Update> (plugin.Get("Wiimote_Update"));
|
Wiimote_Update = reinterpret_cast<TWiimote_Update> (plugin.Get("Wiimote_Update"));
|
||||||
Wiimote_GetAttachedControllers = reinterpret_cast<TWiimote_GetAttachedControllers> (plugin.Get("Wiimote_GetAttachedControllers"));
|
Wiimote_GetAttachedControllers = reinterpret_cast<TWiimote_GetAttachedControllers> (plugin.Get("Wiimote_GetAttachedControllers"));
|
||||||
Wiimote_DoState = reinterpret_cast<TWiimote_DoState> (plugin.Get("Wiimote_DoState"));
|
Wiimote_DoState = reinterpret_cast<TWiimote_DoState> (plugin.Get("Wiimote_DoState"));
|
||||||
|
|
||||||
LOG(MASTER_LOG, "%s: 0x%p", "GetDllInfo", GetDllInfo);
|
LOG(MASTER_LOG, "%s: 0x%p", "GetDllInfo", GetDllInfo);
|
||||||
LOG(MASTER_LOG, "%s: 0x%p", "DllConfig", DllConfig);
|
LOG(MASTER_LOG, "%s: 0x%p", "DllConfig", DllConfig);
|
||||||
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_Initialize", Wiimote_Initialize);
|
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_Initialize", Wiimote_Initialize);
|
||||||
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_Shutdown", Wiimote_Shutdown);
|
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_Shutdown", Wiimote_Shutdown);
|
||||||
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_ControlChannel", Wiimote_ControlChannel);
|
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_ControlChannel", Wiimote_ControlChannel);
|
||||||
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_InterruptChannel", Wiimote_InterruptChannel);
|
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_InterruptChannel", Wiimote_InterruptChannel);
|
||||||
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_Update", Wiimote_Update);
|
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_Update", Wiimote_Update);
|
||||||
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_GetAttachedControllers", Wiimote_GetAttachedControllers);
|
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_GetAttachedControllers", Wiimote_GetAttachedControllers);
|
||||||
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_DoState", Wiimote_DoState);
|
LOG(MASTER_LOG, "%s: 0x%p", "Wiimote_DoState", Wiimote_DoState);
|
||||||
if ((GetDllInfo != 0) &&
|
if ((GetDllInfo != 0) &&
|
||||||
(Wiimote_Initialize != 0) &&
|
(Wiimote_Initialize != 0) &&
|
||||||
(Wiimote_Shutdown != 0) &&
|
(Wiimote_Shutdown != 0) &&
|
||||||
(Wiimote_ControlChannel != 0) &&
|
(Wiimote_ControlChannel != 0) &&
|
||||||
(Wiimote_InterruptChannel != 0) &&
|
(Wiimote_InterruptChannel != 0) &&
|
||||||
(Wiimote_Update != 0) &&
|
(Wiimote_Update != 0) &&
|
||||||
(Wiimote_GetAttachedControllers != 0) &&
|
(Wiimote_GetAttachedControllers != 0) &&
|
||||||
(Wiimote_DoState != 0))
|
(Wiimote_DoState != 0))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UnloadPlugin();
|
UnloadPlugin();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,166 +1,166 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
#include "../../HW/CPU.h"
|
#include "../../HW/CPU.h"
|
||||||
#include "../PPCTables.h"
|
#include "../PPCTables.h"
|
||||||
#include "Interpreter.h"
|
#include "Interpreter.h"
|
||||||
#include "../../Debugger/Debugger_SymbolMap.h"
|
#include "../../Debugger/Debugger_SymbolMap.h"
|
||||||
#include "../../CoreTiming.h"
|
#include "../../CoreTiming.h"
|
||||||
#include "../../Core.h"
|
#include "../../Core.h"
|
||||||
#include "PowerPCDisasm.h"
|
#include "PowerPCDisasm.h"
|
||||||
#include "../../IPC_HLE/WII_IPC_HLE.h"
|
#include "../../IPC_HLE/WII_IPC_HLE.h"
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
u32 last_pc;
|
u32 last_pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function tables
|
// function tables
|
||||||
|
|
||||||
namespace Interpreter
|
namespace Interpreter
|
||||||
{
|
{
|
||||||
// cpu register to keep the code readable
|
// cpu register to keep the code readable
|
||||||
u32 *m_GPR = PowerPC::ppcState.gpr;
|
u32 *m_GPR = PowerPC::ppcState.gpr;
|
||||||
bool m_EndBlock = false;
|
bool m_EndBlock = false;
|
||||||
|
|
||||||
_interpreterInstruction m_opTable[64];
|
_interpreterInstruction m_opTable[64];
|
||||||
_interpreterInstruction m_opTable4[1024];
|
_interpreterInstruction m_opTable4[1024];
|
||||||
_interpreterInstruction m_opTable19[1024];
|
_interpreterInstruction m_opTable19[1024];
|
||||||
_interpreterInstruction m_opTable31[1024];
|
_interpreterInstruction m_opTable31[1024];
|
||||||
_interpreterInstruction m_opTable59[32];
|
_interpreterInstruction m_opTable59[32];
|
||||||
_interpreterInstruction m_opTable63[1024];
|
_interpreterInstruction m_opTable63[1024];
|
||||||
|
|
||||||
void RunTable4(UGeckoInstruction _inst) {m_opTable4 [_inst.SUBOP10](_inst);}
|
void RunTable4(UGeckoInstruction _inst) {m_opTable4 [_inst.SUBOP10](_inst);}
|
||||||
void RunTable19(UGeckoInstruction _inst) {m_opTable19[_inst.SUBOP10](_inst);}
|
void RunTable19(UGeckoInstruction _inst) {m_opTable19[_inst.SUBOP10](_inst);}
|
||||||
void RunTable31(UGeckoInstruction _inst) {m_opTable31[_inst.SUBOP10](_inst);}
|
void RunTable31(UGeckoInstruction _inst) {m_opTable31[_inst.SUBOP10](_inst);}
|
||||||
void RunTable59(UGeckoInstruction _inst) {m_opTable59[_inst.SUBOP5 ](_inst);}
|
void RunTable59(UGeckoInstruction _inst) {m_opTable59[_inst.SUBOP5 ](_inst);}
|
||||||
void RunTable63(UGeckoInstruction _inst) {m_opTable63[_inst.SUBOP10](_inst);}
|
void RunTable63(UGeckoInstruction _inst) {m_opTable63[_inst.SUBOP10](_inst);}
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void patches()
|
void patches()
|
||||||
{
|
{
|
||||||
/* if (Memory::Read_U16(0x90000880) == 0x130b)
|
/* if (Memory::Read_U16(0x90000880) == 0x130b)
|
||||||
{
|
{
|
||||||
PanicAlert("Memory::Read_U16(0x900008800) == 0x130b");
|
PanicAlert("Memory::Read_U16(0x900008800) == 0x130b");
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
/* if (PC == 0x80074cd4)
|
/* if (PC == 0x80074cd4)
|
||||||
{
|
{
|
||||||
u16 command = Common::swap16(Memory::Read_U16(PowerPC::ppcState.gpr[3] + 8));
|
u16 command = Common::swap16(Memory::Read_U16(PowerPC::ppcState.gpr[3] + 8));
|
||||||
if (command == 0x0b13)
|
if (command == 0x0b13)
|
||||||
{
|
{
|
||||||
PanicAlert("command: %x", command);
|
PanicAlert("command: %x", command);
|
||||||
CCPU::Break();
|
CCPU::Break();
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleStepInner(void)
|
void SingleStepInner(void)
|
||||||
{
|
{
|
||||||
static UGeckoInstruction instCode;
|
static UGeckoInstruction instCode;
|
||||||
|
|
||||||
NPC = PC + sizeof(UGeckoInstruction);
|
NPC = PC + sizeof(UGeckoInstruction);
|
||||||
instCode.hex = Memory::Read_Opcode(PC);
|
instCode.hex = Memory::Read_Opcode(PC);
|
||||||
|
|
||||||
UReg_MSR& msr = (UReg_MSR&)MSR;
|
UReg_MSR& msr = (UReg_MSR&)MSR;
|
||||||
if (msr.FP) //If FPU is enabled, just execute
|
if (msr.FP) //If FPU is enabled, just execute
|
||||||
m_opTable[instCode.OPCD](instCode);
|
m_opTable[instCode.OPCD](instCode);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// check if we have to generate a FPU unavailable exception
|
// check if we have to generate a FPU unavailable exception
|
||||||
if (!PPCTables::UsesFPU(instCode))
|
if (!PPCTables::UsesFPU(instCode))
|
||||||
m_opTable[instCode.OPCD](instCode);
|
m_opTable[instCode.OPCD](instCode);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
|
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
m_EndBlock = true;
|
m_EndBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
last_pc = PC;
|
last_pc = PC;
|
||||||
PC = NPC;
|
PC = NPC;
|
||||||
|
|
||||||
if (PowerPC::ppcState.gpr[1] == 0) {
|
if (PowerPC::ppcState.gpr[1] == 0) {
|
||||||
printf("%i Corrupt stack", PowerPC::ppcState.DebugCount);
|
printf("%i Corrupt stack", PowerPC::ppcState.DebugCount);
|
||||||
// CCPU::Break();
|
// CCPU::Break();
|
||||||
}
|
}
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||||
PowerPC::ppcState.DebugCount++;
|
PowerPC::ppcState.DebugCount++;
|
||||||
#endif
|
#endif
|
||||||
patches();
|
patches();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleStep()
|
void SingleStep()
|
||||||
{
|
{
|
||||||
SingleStepInner();
|
SingleStepInner();
|
||||||
|
|
||||||
CoreTiming::slicelength = 1;
|
CoreTiming::slicelength = 1;
|
||||||
CoreTiming::downcount = 0;
|
CoreTiming::downcount = 0;
|
||||||
CoreTiming::Advance();
|
CoreTiming::Advance();
|
||||||
|
|
||||||
if (PowerPC::ppcState.Exceptions)
|
if (PowerPC::ppcState.Exceptions)
|
||||||
{
|
{
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
PC = NPC;
|
PC = NPC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sFastRun - inspired by GCemu
|
// sFastRun - inspired by GCemu
|
||||||
void Run()
|
void Run()
|
||||||
{
|
{
|
||||||
while (!PowerPC::state)
|
while (!PowerPC::state)
|
||||||
{
|
{
|
||||||
//we have to check exceptions at branches apparently (or maybe just rfi?)
|
//we have to check exceptions at branches apparently (or maybe just rfi?)
|
||||||
while (CoreTiming::downcount > 0)
|
while (CoreTiming::downcount > 0)
|
||||||
{
|
{
|
||||||
m_EndBlock = false;
|
m_EndBlock = false;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; !m_EndBlock; i++)
|
for (i = 0; !m_EndBlock; i++)
|
||||||
{
|
{
|
||||||
SingleStepInner();
|
SingleStepInner();
|
||||||
}
|
}
|
||||||
CoreTiming::downcount -= i;
|
CoreTiming::downcount -= i;
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreTiming::Advance();
|
CoreTiming::Advance();
|
||||||
|
|
||||||
if (PowerPC::ppcState.Exceptions)
|
if (PowerPC::ppcState.Exceptions)
|
||||||
{
|
{
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
PC = NPC;
|
PC = NPC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unknown_instruction(UGeckoInstruction _inst)
|
void unknown_instruction(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
CCPU::Break();
|
CCPU::Break();
|
||||||
printf("Last PC = %08x : %s\n", last_pc, DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc));
|
printf("Last PC = %08x : %s\n", last_pc, DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc));
|
||||||
Debugger::PrintCallstack();
|
Debugger::PrintCallstack();
|
||||||
_dbg_assert_msg_(GEKKO, 0, "\nIntCPU: Unknown instr %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR);
|
_dbg_assert_msg_(GEKKO, 0, "\nIntCPU: Unknown instr %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,143 +1,143 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Interpreter.h"
|
#include "Interpreter.h"
|
||||||
#include "../../HW/CPU.h"
|
#include "../../HW/CPU.h"
|
||||||
#include "../../HLE/HLE.h"
|
#include "../../HLE/HLE.h"
|
||||||
#include "../PPCAnalyst.h"
|
#include "../PPCAnalyst.h"
|
||||||
|
|
||||||
namespace Interpreter
|
namespace Interpreter
|
||||||
{
|
{
|
||||||
|
|
||||||
void bx(UGeckoInstruction _inst)
|
void bx(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
if (_inst.LK)
|
if (_inst.LK)
|
||||||
LR = PC + 4;
|
LR = PC + 4;
|
||||||
if (_inst.AA)
|
if (_inst.AA)
|
||||||
NPC = SignExt26(_inst.LI << 2);
|
NPC = SignExt26(_inst.LI << 2);
|
||||||
else
|
else
|
||||||
NPC = PC+SignExt26(_inst.LI << 2);
|
NPC = PC+SignExt26(_inst.LI << 2);
|
||||||
/*
|
/*
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if (_inst.LK)
|
if (_inst.LK)
|
||||||
{
|
{
|
||||||
PPCAnalyst::LogFunctionCall(NPC);
|
PPCAnalyst::LogFunctionCall(NPC);
|
||||||
}
|
}
|
||||||
#endif*/
|
#endif*/
|
||||||
|
|
||||||
m_EndBlock = true;
|
m_EndBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bcx - ugly, straight from PPC manual equations :)
|
// bcx - ugly, straight from PPC manual equations :)
|
||||||
void bcx(UGeckoInstruction _inst)
|
void bcx(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
if ((_inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
if ((_inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
||||||
CTR--;
|
CTR--;
|
||||||
|
|
||||||
const bool true_false = ((_inst.BO >> 3) & 1);
|
const bool true_false = ((_inst.BO >> 3) & 1);
|
||||||
const bool only_counter_check = ((_inst.BO >> 4) & 1);
|
const bool only_counter_check = ((_inst.BO >> 4) & 1);
|
||||||
const bool only_condition_check = ((_inst.BO >> 2) & 1);
|
const bool only_condition_check = ((_inst.BO >> 2) & 1);
|
||||||
int ctr_check = ((CTR != 0) ^ (_inst.BO >> 1)) & 1;
|
int ctr_check = ((CTR != 0) ^ (_inst.BO >> 1)) & 1;
|
||||||
bool counter = only_condition_check || ctr_check;
|
bool counter = only_condition_check || ctr_check;
|
||||||
bool condition = only_counter_check || (GetCRBit(_inst.BI) == u32(true_false));
|
bool condition = only_counter_check || (GetCRBit(_inst.BI) == u32(true_false));
|
||||||
|
|
||||||
if (counter && condition)
|
if (counter && condition)
|
||||||
{
|
{
|
||||||
if (_inst.LK)
|
if (_inst.LK)
|
||||||
LR = PC + 4;
|
LR = PC + 4;
|
||||||
if (_inst.AA)
|
if (_inst.AA)
|
||||||
NPC = SignExt16(_inst.BD << 2);
|
NPC = SignExt16(_inst.BD << 2);
|
||||||
else
|
else
|
||||||
NPC = PC + SignExt16(_inst.BD << 2);
|
NPC = PC + SignExt16(_inst.BD << 2);
|
||||||
}
|
}
|
||||||
m_EndBlock = true;
|
m_EndBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bcctrx(UGeckoInstruction _inst)
|
void bcctrx(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
if ((_inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
if ((_inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
||||||
CTR--;
|
CTR--;
|
||||||
|
|
||||||
int condition = ((_inst.BO>>4) | (GetCRBit(_inst.BI) == ((_inst.BO>>3) & 1))) & 1;
|
int condition = ((_inst.BO>>4) | (GetCRBit(_inst.BI) == ((_inst.BO>>3) & 1))) & 1;
|
||||||
|
|
||||||
if (condition)
|
if (condition)
|
||||||
{
|
{
|
||||||
if (_inst.LK)
|
if (_inst.LK)
|
||||||
LR = PC + 4;
|
LR = PC + 4;
|
||||||
NPC = CTR & (~3);
|
NPC = CTR & (~3);
|
||||||
}
|
}
|
||||||
m_EndBlock = true;
|
m_EndBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bclrx(UGeckoInstruction _inst)
|
void bclrx(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
if ((_inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
if ((_inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
||||||
CTR--;
|
CTR--;
|
||||||
|
|
||||||
int counter = ((_inst.BO >> 2) | ((CTR != 0) ^ (_inst.BO >> 1)))&1;
|
int counter = ((_inst.BO >> 2) | ((CTR != 0) ^ (_inst.BO >> 1)))&1;
|
||||||
int condition = ((_inst.BO >> 4) | (GetCRBit(_inst.BI) == ((_inst.BO >> 3) & 1))) & 1;
|
int condition = ((_inst.BO >> 4) | (GetCRBit(_inst.BI) == ((_inst.BO >> 3) & 1))) & 1;
|
||||||
|
|
||||||
if (counter & condition)
|
if (counter & condition)
|
||||||
{
|
{
|
||||||
NPC = LR & (~3);
|
NPC = LR & (~3);
|
||||||
if (_inst.LK)
|
if (_inst.LK)
|
||||||
LR = PC+4;
|
LR = PC+4;
|
||||||
}
|
}
|
||||||
m_EndBlock = true;
|
m_EndBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HLEFunction(UGeckoInstruction _inst)
|
void HLEFunction(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
m_EndBlock = true;
|
m_EndBlock = true;
|
||||||
HLE::Execute(PC, _inst.hex);
|
HLE::Execute(PC, _inst.hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompiledBlock(UGeckoInstruction _inst)
|
void CompiledBlock(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
_assert_msg_(GEKKO, 0, "CompiledBlock - shouldn't be here!");
|
_assert_msg_(GEKKO, 0, "CompiledBlock - shouldn't be here!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void rfi(UGeckoInstruction _inst)
|
void rfi(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
//Bits SRR1[0,5-9,16<31>23, 25<32>27, 30<33>31] are placed into the corresponding bits of the MSR.
|
//Bits SRR1[0,5-9,16<31>23, 25<32>27, 30<33>31] are placed into the corresponding bits of the MSR.
|
||||||
//MSR[13] is set to 0.
|
//MSR[13] is set to 0.
|
||||||
const int mask = 0x87C0FF73;
|
const int mask = 0x87C0FF73;
|
||||||
MSR = (MSR & ~mask) | (SRR1 & mask);
|
MSR = (MSR & ~mask) | (SRR1 & mask);
|
||||||
MSR &= 0xFFFDFFFF; //TODO: VERIFY
|
MSR &= 0xFFFDFFFF; //TODO: VERIFY
|
||||||
NPC = SRR0; // TODO: VERIFY
|
NPC = SRR0; // TODO: VERIFY
|
||||||
m_EndBlock = true;
|
m_EndBlock = true;
|
||||||
// After an RFI, exceptions should be checked IMMEDIATELY without going back into
|
// After an RFI, exceptions should be checked IMMEDIATELY without going back into
|
||||||
// other code! TODO(ector): fix this properly
|
// other code! TODO(ector): fix this properly
|
||||||
// PowerPC::CheckExceptions();
|
// PowerPC::CheckExceptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void rfid(UGeckoInstruction _inst)
|
void rfid(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
_dbg_assert_msg_(GEKKO,0,"Instruction unimplemented (does this instruction even exist?)","rfid");
|
_dbg_assert_msg_(GEKKO,0,"Instruction unimplemented (does this instruction even exist?)","rfid");
|
||||||
m_EndBlock = true;
|
m_EndBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sc isn't really used for anything important in gc games (just for a write barrier) so we really don't have to emulate it.
|
// sc isn't really used for anything important in gc games (just for a write barrier) so we really don't have to emulate it.
|
||||||
// We do it anyway, though :P
|
// We do it anyway, though :P
|
||||||
void sc(UGeckoInstruction _inst)
|
void sc(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_SYSCALL;
|
PowerPC::ppcState.Exceptions |= EXCEPTION_SYSCALL;
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
m_EndBlock = true;
|
m_EndBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,342 +1,342 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "Interpreter.h"
|
#include "Interpreter.h"
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
|
|
||||||
namespace Interpreter
|
namespace Interpreter
|
||||||
{
|
{
|
||||||
|
|
||||||
// dequantize table
|
// dequantize table
|
||||||
const float m_dequantizeTable[] =
|
const float m_dequantizeTable[] =
|
||||||
{
|
{
|
||||||
1.0 / (1 << 0), 1.0 / (1 << 1), 1.0 / (1 << 2), 1.0 / (1 << 3),
|
1.0 / (1 << 0), 1.0 / (1 << 1), 1.0 / (1 << 2), 1.0 / (1 << 3),
|
||||||
1.0 / (1 << 4), 1.0 / (1 << 5), 1.0 / (1 << 6), 1.0 / (1 << 7),
|
1.0 / (1 << 4), 1.0 / (1 << 5), 1.0 / (1 << 6), 1.0 / (1 << 7),
|
||||||
1.0 / (1 << 8), 1.0 / (1 << 9), 1.0 / (1 << 10), 1.0 / (1 << 11),
|
1.0 / (1 << 8), 1.0 / (1 << 9), 1.0 / (1 << 10), 1.0 / (1 << 11),
|
||||||
1.0 / (1 << 12), 1.0 / (1 << 13), 1.0 / (1 << 14), 1.0 / (1 << 15),
|
1.0 / (1 << 12), 1.0 / (1 << 13), 1.0 / (1 << 14), 1.0 / (1 << 15),
|
||||||
1.0 / (1 << 16), 1.0 / (1 << 17), 1.0 / (1 << 18), 1.0 / (1 << 19),
|
1.0 / (1 << 16), 1.0 / (1 << 17), 1.0 / (1 << 18), 1.0 / (1 << 19),
|
||||||
1.0 / (1 << 20), 1.0 / (1 << 21), 1.0 / (1 << 22), 1.0 / (1 << 23),
|
1.0 / (1 << 20), 1.0 / (1 << 21), 1.0 / (1 << 22), 1.0 / (1 << 23),
|
||||||
1.0 / (1 << 24), 1.0 / (1 << 25), 1.0 / (1 << 26), 1.0 / (1 << 27),
|
1.0 / (1 << 24), 1.0 / (1 << 25), 1.0 / (1 << 26), 1.0 / (1 << 27),
|
||||||
1.0 / (1 << 28), 1.0 / (1 << 29), 1.0 / (1 << 30), 1.0 / (1 << 31),
|
1.0 / (1 << 28), 1.0 / (1 << 29), 1.0 / (1 << 30), 1.0 / (1 << 31),
|
||||||
(1ULL << 32), (1 << 31), (1 << 30), (1 << 29),
|
(1ULL << 32), (1 << 31), (1 << 30), (1 << 29),
|
||||||
(1 << 28), (1 << 27), (1 << 26), (1 << 25),
|
(1 << 28), (1 << 27), (1 << 26), (1 << 25),
|
||||||
(1 << 24), (1 << 23), (1 << 22), (1 << 21),
|
(1 << 24), (1 << 23), (1 << 22), (1 << 21),
|
||||||
(1 << 20), (1 << 19), (1 << 18), (1 << 17),
|
(1 << 20), (1 << 19), (1 << 18), (1 << 17),
|
||||||
(1 << 16), (1 << 15), (1 << 14), (1 << 13),
|
(1 << 16), (1 << 15), (1 << 14), (1 << 13),
|
||||||
(1 << 12), (1 << 11), (1 << 10), (1 << 9),
|
(1 << 12), (1 << 11), (1 << 10), (1 << 9),
|
||||||
(1 << 8), (1 << 7), (1 << 6), (1 << 5),
|
(1 << 8), (1 << 7), (1 << 6), (1 << 5),
|
||||||
(1 << 4), (1 << 3), (1 << 2), (1 << 1),
|
(1 << 4), (1 << 3), (1 << 2), (1 << 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
// quantize table
|
// quantize table
|
||||||
const float m_quantizeTable[] =
|
const float m_quantizeTable[] =
|
||||||
{
|
{
|
||||||
(1 << 0), (1 << 1), (1 << 2), (1 << 3),
|
(1 << 0), (1 << 1), (1 << 2), (1 << 3),
|
||||||
(1 << 4), (1 << 5), (1 << 6), (1 << 7),
|
(1 << 4), (1 << 5), (1 << 6), (1 << 7),
|
||||||
(1 << 8), (1 << 9), (1 << 10), (1 << 11),
|
(1 << 8), (1 << 9), (1 << 10), (1 << 11),
|
||||||
(1 << 12), (1 << 13), (1 << 14), (1 << 15),
|
(1 << 12), (1 << 13), (1 << 14), (1 << 15),
|
||||||
(1 << 16), (1 << 17), (1 << 18), (1 << 19),
|
(1 << 16), (1 << 17), (1 << 18), (1 << 19),
|
||||||
(1 << 20), (1 << 21), (1 << 22), (1 << 23),
|
(1 << 20), (1 << 21), (1 << 22), (1 << 23),
|
||||||
(1 << 24), (1 << 25), (1 << 26), (1 << 27),
|
(1 << 24), (1 << 25), (1 << 26), (1 << 27),
|
||||||
(1 << 28), (1 << 29), (1 << 30), (1 << 31),
|
(1 << 28), (1 << 29), (1 << 30), (1 << 31),
|
||||||
1.0 / (1ULL << 32), 1.0 / (1 << 31), 1.0 / (1 << 30), 1.0 / (1 << 29),
|
1.0 / (1ULL << 32), 1.0 / (1 << 31), 1.0 / (1 << 30), 1.0 / (1 << 29),
|
||||||
1.0 / (1 << 28), 1.0 / (1 << 27), 1.0 / (1 << 26), 1.0 / (1 << 25),
|
1.0 / (1 << 28), 1.0 / (1 << 27), 1.0 / (1 << 26), 1.0 / (1 << 25),
|
||||||
1.0 / (1 << 24), 1.0 / (1 << 23), 1.0 / (1 << 22), 1.0 / (1 << 21),
|
1.0 / (1 << 24), 1.0 / (1 << 23), 1.0 / (1 << 22), 1.0 / (1 << 21),
|
||||||
1.0 / (1 << 20), 1.0 / (1 << 19), 1.0 / (1 << 18), 1.0 / (1 << 17),
|
1.0 / (1 << 20), 1.0 / (1 << 19), 1.0 / (1 << 18), 1.0 / (1 << 17),
|
||||||
1.0 / (1 << 16), 1.0 / (1 << 15), 1.0 / (1 << 14), 1.0 / (1 << 13),
|
1.0 / (1 << 16), 1.0 / (1 << 15), 1.0 / (1 << 14), 1.0 / (1 << 13),
|
||||||
1.0 / (1 << 12), 1.0 / (1 << 11), 1.0 / (1 << 10), 1.0 / (1 << 9),
|
1.0 / (1 << 12), 1.0 / (1 << 11), 1.0 / (1 << 10), 1.0 / (1 << 9),
|
||||||
1.0 / (1 << 8), 1.0 / (1 << 7), 1.0 / (1 << 6), 1.0 / (1 << 5),
|
1.0 / (1 << 8), 1.0 / (1 << 7), 1.0 / (1 << 6), 1.0 / (1 << 5),
|
||||||
1.0 / (1 << 4), 1.0 / (1 << 3), 1.0 / (1 << 2), 1.0 / (1 << 1),
|
1.0 / (1 << 4), 1.0 / (1 << 3), 1.0 / (1 << 2), 1.0 / (1 << 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline T CLAMP(T a, T bottom, T top) {
|
inline T CLAMP(T a, T bottom, T top) {
|
||||||
if (a > top) return top;
|
if (a > top) return top;
|
||||||
if (a < bottom) return bottom;
|
if (a < bottom) return bottom;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Helper_Quantize(const u32 _Addr, const float _fValue,
|
void Helper_Quantize(const u32 _Addr, const float _fValue,
|
||||||
const EQuantizeType _quantizeType, const unsigned int _uScale)
|
const EQuantizeType _quantizeType, const unsigned int _uScale)
|
||||||
{
|
{
|
||||||
switch(_quantizeType)
|
switch(_quantizeType)
|
||||||
{
|
{
|
||||||
case QUANTIZE_FLOAT:
|
case QUANTIZE_FLOAT:
|
||||||
Memory::Write_U32(*(u32*)&_fValue,_Addr);
|
Memory::Write_U32(*(u32*)&_fValue,_Addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// used for THP player
|
// used for THP player
|
||||||
case QUANTIZE_U8:
|
case QUANTIZE_U8:
|
||||||
{
|
{
|
||||||
float fResult = CLAMP(_fValue * m_quantizeTable[_uScale], 0.0f, 255.0f);
|
float fResult = CLAMP(_fValue * m_quantizeTable[_uScale], 0.0f, 255.0f);
|
||||||
Memory::Write_U8((u8)fResult, _Addr);
|
Memory::Write_U8((u8)fResult, _Addr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QUANTIZE_U16:
|
case QUANTIZE_U16:
|
||||||
{
|
{
|
||||||
float fResult = CLAMP(_fValue * m_quantizeTable[_uScale], 0.0f, 65535.0f);
|
float fResult = CLAMP(_fValue * m_quantizeTable[_uScale], 0.0f, 65535.0f);
|
||||||
Memory::Write_U16((u16)fResult, _Addr);
|
Memory::Write_U16((u16)fResult, _Addr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QUANTIZE_S8:
|
case QUANTIZE_S8:
|
||||||
{
|
{
|
||||||
float fResult = CLAMP(_fValue * m_quantizeTable[_uScale], -128.0f, 127.0f);
|
float fResult = CLAMP(_fValue * m_quantizeTable[_uScale], -128.0f, 127.0f);
|
||||||
Memory::Write_U8((u8)(s8)fResult, _Addr);
|
Memory::Write_U8((u8)(s8)fResult, _Addr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QUANTIZE_S16:
|
case QUANTIZE_S16:
|
||||||
{
|
{
|
||||||
float fResult = CLAMP(_fValue * m_quantizeTable[_uScale], -32768.0f, 32767.0f);
|
float fResult = CLAMP(_fValue * m_quantizeTable[_uScale], -32768.0f, 32767.0f);
|
||||||
Memory::Write_U16((u16)(s16)fResult, _Addr);
|
Memory::Write_U16((u16)(s16)fResult, _Addr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_dbg_assert_msg_(GEKKO,0,"PS dequantize","Unknown type to read");
|
_dbg_assert_msg_(GEKKO,0,"PS dequantize","Unknown type to read");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float Helper_Dequantize(const u32 _Addr, const EQuantizeType _quantizeType,
|
float Helper_Dequantize(const u32 _Addr, const EQuantizeType _quantizeType,
|
||||||
const unsigned int _uScale)
|
const unsigned int _uScale)
|
||||||
{
|
{
|
||||||
// dequantize the value
|
// dequantize the value
|
||||||
float fResult;
|
float fResult;
|
||||||
switch(_quantizeType)
|
switch(_quantizeType)
|
||||||
{
|
{
|
||||||
case QUANTIZE_FLOAT:
|
case QUANTIZE_FLOAT:
|
||||||
{
|
{
|
||||||
u32 dwValue = Memory::Read_U32(_Addr);
|
u32 dwValue = Memory::Read_U32(_Addr);
|
||||||
fResult = *(float*)&dwValue;
|
fResult = *(float*)&dwValue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QUANTIZE_U8:
|
case QUANTIZE_U8:
|
||||||
fResult = static_cast<float>(Memory::Read_U8(_Addr)) * m_dequantizeTable[_uScale];
|
fResult = static_cast<float>(Memory::Read_U8(_Addr)) * m_dequantizeTable[_uScale];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QUANTIZE_U16:
|
case QUANTIZE_U16:
|
||||||
fResult = static_cast<float>(Memory::Read_U16(_Addr)) * m_dequantizeTable[_uScale];
|
fResult = static_cast<float>(Memory::Read_U16(_Addr)) * m_dequantizeTable[_uScale];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QUANTIZE_S8:
|
case QUANTIZE_S8:
|
||||||
fResult = static_cast<float>((s8)Memory::Read_U8(_Addr)) * m_dequantizeTable[_uScale];
|
fResult = static_cast<float>((s8)Memory::Read_U8(_Addr)) * m_dequantizeTable[_uScale];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// used for THP player
|
// used for THP player
|
||||||
case QUANTIZE_S16:
|
case QUANTIZE_S16:
|
||||||
fResult = static_cast<float>((s16)Memory::Read_U16(_Addr)) * m_dequantizeTable[_uScale];
|
fResult = static_cast<float>((s16)Memory::Read_U16(_Addr)) * m_dequantizeTable[_uScale];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_dbg_assert_msg_(GEKKO,0,"PS dequantize","Unknown type to read");
|
_dbg_assert_msg_(GEKKO,0,"PS dequantize","Unknown type to read");
|
||||||
fResult = 0;
|
fResult = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fResult;
|
return fResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
void psq_l(UGeckoInstruction _inst)
|
void psq_l(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
const UGQR gqr(rSPR(SPR_GQR0 + _inst.I));
|
const UGQR gqr(rSPR(SPR_GQR0 + _inst.I));
|
||||||
const EQuantizeType ldType = static_cast<EQuantizeType>(gqr.LD_TYPE);
|
const EQuantizeType ldType = static_cast<EQuantizeType>(gqr.LD_TYPE);
|
||||||
const unsigned int ldScale = gqr.LD_SCALE;
|
const unsigned int ldScale = gqr.LD_SCALE;
|
||||||
const u32 EA = _inst.RA ? (m_GPR[_inst.RA] + _inst.SIMM_12) : _inst.SIMM_12;
|
const u32 EA = _inst.RA ? (m_GPR[_inst.RA] + _inst.SIMM_12) : _inst.SIMM_12;
|
||||||
|
|
||||||
int c = 4;
|
int c = 4;
|
||||||
if ((ldType == QUANTIZE_U8) || (ldType == QUANTIZE_S8)) c = 0x1;
|
if ((ldType == QUANTIZE_U8) || (ldType == QUANTIZE_S8)) c = 0x1;
|
||||||
if ((ldType == QUANTIZE_U16) || (ldType == QUANTIZE_S16)) c = 0x2;
|
if ((ldType == QUANTIZE_U16) || (ldType == QUANTIZE_S16)) c = 0x2;
|
||||||
|
|
||||||
if (_inst.W == 0)
|
if (_inst.W == 0)
|
||||||
{
|
{
|
||||||
rPS0(_inst.RS) = Helper_Dequantize(EA, ldType, ldScale);
|
rPS0(_inst.RS) = Helper_Dequantize(EA, ldType, ldScale);
|
||||||
rPS1(_inst.RS) = Helper_Dequantize(EA+c, ldType, ldScale);
|
rPS1(_inst.RS) = Helper_Dequantize(EA+c, ldType, ldScale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rPS0(_inst.RS) = Helper_Dequantize(EA, ldType, ldScale);
|
rPS0(_inst.RS) = Helper_Dequantize(EA, ldType, ldScale);
|
||||||
rPS1(_inst.RS) = 1.0f;
|
rPS1(_inst.RS) = 1.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void psq_lu(UGeckoInstruction _inst)
|
void psq_lu(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
const UGQR gqr(rSPR(SPR_GQR0 + _inst.I));
|
const UGQR gqr(rSPR(SPR_GQR0 + _inst.I));
|
||||||
const EQuantizeType ldType = static_cast<EQuantizeType>(gqr.LD_TYPE);
|
const EQuantizeType ldType = static_cast<EQuantizeType>(gqr.LD_TYPE);
|
||||||
const unsigned int ldScale = gqr.LD_SCALE;
|
const unsigned int ldScale = gqr.LD_SCALE;
|
||||||
const u32 EA = m_GPR[_inst.RA] + _inst.SIMM_12;
|
const u32 EA = m_GPR[_inst.RA] + _inst.SIMM_12;
|
||||||
|
|
||||||
int c = 4;
|
int c = 4;
|
||||||
if ((ldType == 4) || (ldType == 6)) c = 0x1;
|
if ((ldType == 4) || (ldType == 6)) c = 0x1;
|
||||||
if ((ldType == 5) || (ldType == 7)) c = 0x2;
|
if ((ldType == 5) || (ldType == 7)) c = 0x2;
|
||||||
|
|
||||||
if (_inst.W == 0)
|
if (_inst.W == 0)
|
||||||
{
|
{
|
||||||
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
||||||
rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale );
|
rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
||||||
rPS1(_inst.RS) = 1.0f;
|
rPS1(_inst.RS) = 1.0f;
|
||||||
}
|
}
|
||||||
m_GPR[_inst.RA] = EA;
|
m_GPR[_inst.RA] = EA;
|
||||||
}
|
}
|
||||||
|
|
||||||
void psq_st(UGeckoInstruction _inst)
|
void psq_st(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
const UGQR gqr(rSPR(SPR_GQR0 + _inst.I));
|
const UGQR gqr(rSPR(SPR_GQR0 + _inst.I));
|
||||||
const EQuantizeType stType = static_cast<EQuantizeType>(gqr.ST_TYPE);
|
const EQuantizeType stType = static_cast<EQuantizeType>(gqr.ST_TYPE);
|
||||||
const unsigned int stScale = gqr.ST_SCALE;
|
const unsigned int stScale = gqr.ST_SCALE;
|
||||||
const u32 EA = _inst.RA ? (m_GPR[_inst.RA] + _inst.SIMM_12) : _inst.SIMM_12;
|
const u32 EA = _inst.RA ? (m_GPR[_inst.RA] + _inst.SIMM_12) : _inst.SIMM_12;
|
||||||
|
|
||||||
int c = 4;
|
int c = 4;
|
||||||
if ((stType == 4) || (stType == 6)) c = 0x1;
|
if ((stType == 4) || (stType == 6)) c = 0x1;
|
||||||
if ((stType == 5) || (stType == 7)) c = 0x2;
|
if ((stType == 5) || (stType == 7)) c = 0x2;
|
||||||
|
|
||||||
if (_inst.W == 0)
|
if (_inst.W == 0)
|
||||||
{
|
{
|
||||||
Helper_Quantize( EA, (float)rPS0(_inst.RS), stType, stScale );
|
Helper_Quantize( EA, (float)rPS0(_inst.RS), stType, stScale );
|
||||||
Helper_Quantize( EA+c, (float)rPS1(_inst.RS), stType, stScale );
|
Helper_Quantize( EA+c, (float)rPS1(_inst.RS), stType, stScale );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Helper_Quantize( EA, (float)rPS0(_inst.RS), stType, stScale );
|
Helper_Quantize( EA, (float)rPS0(_inst.RS), stType, stScale );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void psq_stu(UGeckoInstruction _inst)
|
void psq_stu(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
const UGQR gqr(rSPR(SPR_GQR0 + _inst.I));
|
const UGQR gqr(rSPR(SPR_GQR0 + _inst.I));
|
||||||
const EQuantizeType stType = static_cast<EQuantizeType>(gqr.ST_TYPE);
|
const EQuantizeType stType = static_cast<EQuantizeType>(gqr.ST_TYPE);
|
||||||
const unsigned int stScale = gqr.ST_SCALE;
|
const unsigned int stScale = gqr.ST_SCALE;
|
||||||
const u32 EA = m_GPR[_inst.RA] + _inst.SIMM_12;
|
const u32 EA = m_GPR[_inst.RA] + _inst.SIMM_12;
|
||||||
|
|
||||||
int c = 4;
|
int c = 4;
|
||||||
if ((stType == 4) || (stType == 6)) c = 0x1;
|
if ((stType == 4) || (stType == 6)) c = 0x1;
|
||||||
if ((stType == 5) || (stType == 7)) c = 0x2;
|
if ((stType == 5) || (stType == 7)) c = 0x2;
|
||||||
|
|
||||||
if (_inst.W == 0)
|
if (_inst.W == 0)
|
||||||
{
|
{
|
||||||
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
||||||
Helper_Quantize(EA+c, (float)rPS1(_inst.RS), stType, stScale);
|
Helper_Quantize(EA+c, (float)rPS1(_inst.RS), stType, stScale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
||||||
}
|
}
|
||||||
m_GPR[_inst.RA] = EA;
|
m_GPR[_inst.RA] = EA;
|
||||||
}
|
}
|
||||||
|
|
||||||
void psq_lx(UGeckoInstruction _inst)
|
void psq_lx(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
const UGQR gqr(rSPR(SPR_GQR0 + _inst.Ix));
|
const UGQR gqr(rSPR(SPR_GQR0 + _inst.Ix));
|
||||||
const EQuantizeType ldType = static_cast<EQuantizeType>(gqr.LD_TYPE);
|
const EQuantizeType ldType = static_cast<EQuantizeType>(gqr.LD_TYPE);
|
||||||
const unsigned int ldScale = gqr.LD_SCALE;
|
const unsigned int ldScale = gqr.LD_SCALE;
|
||||||
const u32 EA = _inst.RA ? (m_GPR[_inst.RA] + m_GPR[_inst.RB]) : m_GPR[_inst.RB];
|
const u32 EA = _inst.RA ? (m_GPR[_inst.RA] + m_GPR[_inst.RB]) : m_GPR[_inst.RB];
|
||||||
|
|
||||||
int c = 4;
|
int c = 4;
|
||||||
if ((ldType == 4) || (ldType == 6)) c = 0x1;
|
if ((ldType == 4) || (ldType == 6)) c = 0x1;
|
||||||
if ((ldType == 5) || (ldType == 7)) c = 0x2;
|
if ((ldType == 5) || (ldType == 7)) c = 0x2;
|
||||||
|
|
||||||
if (_inst.Wx == 0)
|
if (_inst.Wx == 0)
|
||||||
{
|
{
|
||||||
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
||||||
rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale );
|
rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
||||||
rPS1(_inst.RS) = 1.0f;
|
rPS1(_inst.RS) = 1.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void psq_stx(UGeckoInstruction _inst)
|
void psq_stx(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
const UGQR gqr(rSPR(SPR_GQR0 + _inst.Ix));
|
const UGQR gqr(rSPR(SPR_GQR0 + _inst.Ix));
|
||||||
const EQuantizeType stType = static_cast<EQuantizeType>(gqr.ST_TYPE);
|
const EQuantizeType stType = static_cast<EQuantizeType>(gqr.ST_TYPE);
|
||||||
const unsigned int stScale = gqr.ST_SCALE;
|
const unsigned int stScale = gqr.ST_SCALE;
|
||||||
const u32 EA = _inst.RA ? (m_GPR[_inst.RA] + m_GPR[_inst.RB]) : m_GPR[_inst.RB];
|
const u32 EA = _inst.RA ? (m_GPR[_inst.RA] + m_GPR[_inst.RB]) : m_GPR[_inst.RB];
|
||||||
|
|
||||||
int c = 4;
|
int c = 4;
|
||||||
if ((stType == 4) || (stType == 6)) c = 0x1;
|
if ((stType == 4) || (stType == 6)) c = 0x1;
|
||||||
if ((stType == 5) || (stType == 7)) c = 0x2;
|
if ((stType == 5) || (stType == 7)) c = 0x2;
|
||||||
|
|
||||||
if (_inst.Wx == 0)
|
if (_inst.Wx == 0)
|
||||||
{
|
{
|
||||||
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
||||||
Helper_Quantize(EA+c, (float)rPS1(_inst.RS), stType, stScale);
|
Helper_Quantize(EA+c, (float)rPS1(_inst.RS), stType, stScale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void psq_lux(UGeckoInstruction _inst)
|
void psq_lux(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
const UGQR gqr(rSPR(SPR_GQR0 + _inst.Ix));
|
const UGQR gqr(rSPR(SPR_GQR0 + _inst.Ix));
|
||||||
const EQuantizeType ldType = static_cast<EQuantizeType>(gqr.LD_TYPE);
|
const EQuantizeType ldType = static_cast<EQuantizeType>(gqr.LD_TYPE);
|
||||||
const unsigned int ldScale = gqr.LD_SCALE;
|
const unsigned int ldScale = gqr.LD_SCALE;
|
||||||
const u32 EA = m_GPR[_inst.RA] + m_GPR[_inst.RB];
|
const u32 EA = m_GPR[_inst.RA] + m_GPR[_inst.RB];
|
||||||
|
|
||||||
int c = 4;
|
int c = 4;
|
||||||
if ((ldType == 4) || (ldType == 6)) c = 0x1;
|
if ((ldType == 4) || (ldType == 6)) c = 0x1;
|
||||||
if ((ldType == 5) || (ldType == 7)) c = 0x2;
|
if ((ldType == 5) || (ldType == 7)) c = 0x2;
|
||||||
|
|
||||||
if (_inst.Wx == 0)
|
if (_inst.Wx == 0)
|
||||||
{
|
{
|
||||||
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
||||||
rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale );
|
rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
|
||||||
rPS1(_inst.RS) = 1.0f;
|
rPS1(_inst.RS) = 1.0f;
|
||||||
}
|
}
|
||||||
m_GPR[_inst.RA] = EA;
|
m_GPR[_inst.RA] = EA;
|
||||||
}
|
}
|
||||||
|
|
||||||
void psq_stux(UGeckoInstruction _inst)
|
void psq_stux(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
const UGQR gqr(rSPR(SPR_GQR0 + _inst.Ix));
|
const UGQR gqr(rSPR(SPR_GQR0 + _inst.Ix));
|
||||||
const EQuantizeType stType = static_cast<EQuantizeType>(gqr.ST_TYPE);
|
const EQuantizeType stType = static_cast<EQuantizeType>(gqr.ST_TYPE);
|
||||||
const unsigned int stScale = gqr.ST_SCALE;
|
const unsigned int stScale = gqr.ST_SCALE;
|
||||||
const u32 EA = m_GPR[_inst.RA] + m_GPR[_inst.RB];
|
const u32 EA = m_GPR[_inst.RA] + m_GPR[_inst.RB];
|
||||||
|
|
||||||
int c = 4;
|
int c = 4;
|
||||||
if ((stType == 4) || (stType == 6)) c = 0x1;
|
if ((stType == 4) || (stType == 6)) c = 0x1;
|
||||||
if ((stType == 5) || (stType == 7)) c = 0x2;
|
if ((stType == 5) || (stType == 7)) c = 0x2;
|
||||||
|
|
||||||
if (_inst.Wx == 0)
|
if (_inst.Wx == 0)
|
||||||
{
|
{
|
||||||
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
||||||
Helper_Quantize(EA+c, (float)rPS1(_inst.RS), stType, stScale);
|
Helper_Quantize(EA+c, (float)rPS1(_inst.RS), stType, stScale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
Helper_Quantize(EA, (float)rPS0(_inst.RS), stType, stScale);
|
||||||
}
|
}
|
||||||
m_GPR[_inst.RA] = EA;
|
m_GPR[_inst.RA] = EA;
|
||||||
|
|
||||||
} // namespace=======
|
} // namespace=======
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,261 +1,261 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "Interpreter.h"
|
#include "Interpreter.h"
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
|
|
||||||
namespace Interpreter
|
namespace Interpreter
|
||||||
{
|
{
|
||||||
|
|
||||||
// These "binary instructions" do not alter FPSCR.
|
// These "binary instructions" do not alter FPSCR.
|
||||||
void ps_sel(UGeckoInstruction _inst)
|
void ps_sel(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = static_cast<float>((rPS0(_inst.FA) >= -0.0) ? rPS0(_inst.FC) : rPS0(_inst.FB));
|
rPS0(_inst.FD) = static_cast<float>((rPS0(_inst.FA) >= -0.0) ? rPS0(_inst.FC) : rPS0(_inst.FB));
|
||||||
rPS1(_inst.FD) = static_cast<float>((rPS1(_inst.FA) >= -0.0) ? rPS1(_inst.FC) : rPS1(_inst.FB));
|
rPS1(_inst.FD) = static_cast<float>((rPS1(_inst.FA) >= -0.0) ? rPS1(_inst.FC) : rPS1(_inst.FB));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_neg(UGeckoInstruction _inst)
|
void ps_neg(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
riPS0(_inst.FD) = riPS0(_inst.FB) ^ (1ULL << 63);
|
riPS0(_inst.FD) = riPS0(_inst.FB) ^ (1ULL << 63);
|
||||||
riPS1(_inst.FD) = riPS1(_inst.FB) ^ (1ULL << 63);
|
riPS1(_inst.FD) = riPS1(_inst.FB) ^ (1ULL << 63);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_mr(UGeckoInstruction _inst)
|
void ps_mr(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = rPS0(_inst.FB);
|
rPS0(_inst.FD) = rPS0(_inst.FB);
|
||||||
rPS1(_inst.FD) = rPS1(_inst.FB);
|
rPS1(_inst.FD) = rPS1(_inst.FB);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_nabs(UGeckoInstruction _inst)
|
void ps_nabs(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
riPS0(_inst.FD) = riPS0(_inst.FB) | (1ULL << 63);
|
riPS0(_inst.FD) = riPS0(_inst.FB) | (1ULL << 63);
|
||||||
riPS1(_inst.FD) = riPS1(_inst.FB) | (1ULL << 63);
|
riPS1(_inst.FD) = riPS1(_inst.FB) | (1ULL << 63);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_abs(UGeckoInstruction _inst)
|
void ps_abs(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
riPS0(_inst.FD) = riPS0(_inst.FB) &~ (1ULL << 63);
|
riPS0(_inst.FD) = riPS0(_inst.FB) &~ (1ULL << 63);
|
||||||
riPS1(_inst.FD) = riPS1(_inst.FB) &~ (1ULL << 63);
|
riPS1(_inst.FD) = riPS1(_inst.FB) &~ (1ULL << 63);
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are just moves, double is OK.
|
// These are just moves, double is OK.
|
||||||
void ps_merge00(UGeckoInstruction _inst)
|
void ps_merge00(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double p0 = rPS0(_inst.FA);
|
double p0 = rPS0(_inst.FA);
|
||||||
double p1 = rPS0(_inst.FB);
|
double p1 = rPS0(_inst.FB);
|
||||||
rPS0(_inst.FD) = p0;
|
rPS0(_inst.FD) = p0;
|
||||||
rPS1(_inst.FD) = p1;
|
rPS1(_inst.FD) = p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_merge01(UGeckoInstruction _inst)
|
void ps_merge01(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double p0 = rPS0(_inst.FA);
|
double p0 = rPS0(_inst.FA);
|
||||||
double p1 = rPS1(_inst.FB);
|
double p1 = rPS1(_inst.FB);
|
||||||
rPS0(_inst.FD) = p0;
|
rPS0(_inst.FD) = p0;
|
||||||
rPS1(_inst.FD) = p1;
|
rPS1(_inst.FD) = p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_merge10(UGeckoInstruction _inst)
|
void ps_merge10(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double p0 = rPS1(_inst.FA);
|
double p0 = rPS1(_inst.FA);
|
||||||
double p1 = rPS0(_inst.FB);
|
double p1 = rPS0(_inst.FB);
|
||||||
rPS0(_inst.FD) = p0;
|
rPS0(_inst.FD) = p0;
|
||||||
rPS1(_inst.FD) = p1;
|
rPS1(_inst.FD) = p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_merge11(UGeckoInstruction _inst)
|
void ps_merge11(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double p0 = rPS1(_inst.FA);
|
double p0 = rPS1(_inst.FA);
|
||||||
double p1 = rPS1(_inst.FB);
|
double p1 = rPS1(_inst.FB);
|
||||||
rPS0(_inst.FD) = p0;
|
rPS0(_inst.FD) = p0;
|
||||||
rPS1(_inst.FD) = p1;
|
rPS1(_inst.FD) = p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// From here on, the real deal.
|
// From here on, the real deal.
|
||||||
|
|
||||||
void ps_div(UGeckoInstruction _inst)
|
void ps_div(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = static_cast<float>(rPS0(_inst.FA) / rPS0(_inst.FB));
|
rPS0(_inst.FD) = static_cast<float>(rPS0(_inst.FA) / rPS0(_inst.FB));
|
||||||
rPS1(_inst.FD) = static_cast<float>(rPS1(_inst.FA) / rPS1(_inst.FB));
|
rPS1(_inst.FD) = static_cast<float>(rPS1(_inst.FA) / rPS1(_inst.FB));
|
||||||
FPSCR.FI = 0;
|
FPSCR.FI = 0;
|
||||||
if (fabs(rPS0(_inst.FB)) == 0.0) {
|
if (fabs(rPS0(_inst.FB)) == 0.0) {
|
||||||
FPSCR.ZX = 1;
|
FPSCR.ZX = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_sub(UGeckoInstruction _inst)
|
void ps_sub(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = static_cast<float>(rPS0(_inst.FA) - rPS0(_inst.FB));
|
rPS0(_inst.FD) = static_cast<float>(rPS0(_inst.FA) - rPS0(_inst.FB));
|
||||||
rPS1(_inst.FD) = static_cast<float>(rPS1(_inst.FA) - rPS1(_inst.FB));
|
rPS1(_inst.FD) = static_cast<float>(rPS1(_inst.FA) - rPS1(_inst.FB));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_add(UGeckoInstruction _inst)
|
void ps_add(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = static_cast<float>(rPS0(_inst.FA) + rPS0(_inst.FB));
|
rPS0(_inst.FD) = static_cast<float>(rPS0(_inst.FA) + rPS0(_inst.FB));
|
||||||
rPS1(_inst.FD) = static_cast<float>(rPS1(_inst.FA) + rPS1(_inst.FB));
|
rPS1(_inst.FD) = static_cast<float>(rPS1(_inst.FA) + rPS1(_inst.FB));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_res(UGeckoInstruction _inst)
|
void ps_res(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = 1.0f / static_cast<float>(rPS0(_inst.FB));
|
rPS0(_inst.FD) = 1.0f / static_cast<float>(rPS0(_inst.FB));
|
||||||
rPS1(_inst.FD) = 1.0f / static_cast<float>(rPS1(_inst.FB));
|
rPS1(_inst.FD) = 1.0f / static_cast<float>(rPS1(_inst.FB));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_mul(UGeckoInstruction _inst)
|
void ps_mul(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = static_cast<float>(rPS0(_inst.FA) * rPS0(_inst.FC));
|
rPS0(_inst.FD) = static_cast<float>(rPS0(_inst.FA) * rPS0(_inst.FC));
|
||||||
rPS1(_inst.FD) = static_cast<float>(rPS1(_inst.FA) * rPS1(_inst.FC));
|
rPS1(_inst.FD) = static_cast<float>(rPS1(_inst.FA) * rPS1(_inst.FC));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_rsqrte(UGeckoInstruction _inst)
|
void ps_rsqrte(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = static_cast<double>(1.0f / sqrtf((float)rPS0(_inst.FB)));
|
rPS0(_inst.FD) = static_cast<double>(1.0f / sqrtf((float)rPS0(_inst.FB)));
|
||||||
rPS1(_inst.FD) = static_cast<double>(1.0f / sqrtf((float)rPS1(_inst.FB)));
|
rPS1(_inst.FD) = static_cast<double>(1.0f / sqrtf((float)rPS1(_inst.FB)));
|
||||||
if (fabs(rPS0(_inst.FB)) == 0.0) {
|
if (fabs(rPS0(_inst.FB)) == 0.0) {
|
||||||
FPSCR.ZX = 1;
|
FPSCR.ZX = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_msub(UGeckoInstruction _inst)
|
void ps_msub(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = static_cast<float>((rPS0(_inst.FA) * rPS0(_inst.FC)) - rPS0(_inst.FB));
|
rPS0(_inst.FD) = static_cast<float>((rPS0(_inst.FA) * rPS0(_inst.FC)) - rPS0(_inst.FB));
|
||||||
rPS1(_inst.FD) = static_cast<float>((rPS1(_inst.FA) * rPS1(_inst.FC)) - rPS1(_inst.FB));
|
rPS1(_inst.FD) = static_cast<float>((rPS1(_inst.FA) * rPS1(_inst.FC)) - rPS1(_inst.FB));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_madd(UGeckoInstruction _inst)
|
void ps_madd(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = static_cast<float>((rPS0(_inst.FA) * rPS0(_inst.FC)) + rPS0(_inst.FB));
|
rPS0(_inst.FD) = static_cast<float>((rPS0(_inst.FA) * rPS0(_inst.FC)) + rPS0(_inst.FB));
|
||||||
rPS1(_inst.FD) = static_cast<float>((rPS1(_inst.FA) * rPS1(_inst.FC)) + rPS1(_inst.FB));
|
rPS1(_inst.FD) = static_cast<float>((rPS1(_inst.FA) * rPS1(_inst.FC)) + rPS1(_inst.FB));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_nmsub(UGeckoInstruction _inst)
|
void ps_nmsub(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = static_cast<float>(-(rPS0(_inst.FA) * rPS0(_inst.FC) - rPS0(_inst.FB)));
|
rPS0(_inst.FD) = static_cast<float>(-(rPS0(_inst.FA) * rPS0(_inst.FC) - rPS0(_inst.FB)));
|
||||||
rPS1(_inst.FD) = static_cast<float>(-(rPS1(_inst.FA) * rPS1(_inst.FC) - rPS1(_inst.FB)));
|
rPS1(_inst.FD) = static_cast<float>(-(rPS1(_inst.FA) * rPS1(_inst.FC) - rPS1(_inst.FB)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_nmadd(UGeckoInstruction _inst)
|
void ps_nmadd(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = static_cast<float>(-(rPS0(_inst.FA) * rPS0(_inst.FC) + rPS0(_inst.FB)));
|
rPS0(_inst.FD) = static_cast<float>(-(rPS0(_inst.FA) * rPS0(_inst.FC) + rPS0(_inst.FB)));
|
||||||
rPS1(_inst.FD) = static_cast<float>(-(rPS1(_inst.FA) * rPS1(_inst.FC) + rPS1(_inst.FB)));
|
rPS1(_inst.FD) = static_cast<float>(-(rPS1(_inst.FA) * rPS1(_inst.FC) + rPS1(_inst.FB)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_sum0(UGeckoInstruction _inst)
|
void ps_sum0(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double p0 = (float)(rPS0(_inst.FA) + rPS1(_inst.FB));
|
double p0 = (float)(rPS0(_inst.FA) + rPS1(_inst.FB));
|
||||||
double p1 = (float)(rPS1(_inst.FC));
|
double p1 = (float)(rPS1(_inst.FC));
|
||||||
rPS0(_inst.FD) = p0;
|
rPS0(_inst.FD) = p0;
|
||||||
rPS1(_inst.FD) = p1;
|
rPS1(_inst.FD) = p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_sum1(UGeckoInstruction _inst)
|
void ps_sum1(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double p0 = rPS0(_inst.FC);
|
double p0 = rPS0(_inst.FC);
|
||||||
double p1 = rPS0(_inst.FA) + rPS1(_inst.FB);
|
double p1 = rPS0(_inst.FA) + rPS1(_inst.FB);
|
||||||
rPS0(_inst.FD) = p0;
|
rPS0(_inst.FD) = p0;
|
||||||
rPS1(_inst.FD) = p1;
|
rPS1(_inst.FD) = p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_muls0(UGeckoInstruction _inst)
|
void ps_muls0(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double p0 = rPS0(_inst.FA) * rPS0(_inst.FC);
|
double p0 = rPS0(_inst.FA) * rPS0(_inst.FC);
|
||||||
double p1 = rPS1(_inst.FA) * rPS0(_inst.FC);
|
double p1 = rPS1(_inst.FA) * rPS0(_inst.FC);
|
||||||
rPS0(_inst.FD) = p0;
|
rPS0(_inst.FD) = p0;
|
||||||
rPS1(_inst.FD) = p1;
|
rPS1(_inst.FD) = p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_muls1(UGeckoInstruction _inst)
|
void ps_muls1(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double p0 = rPS0(_inst.FA) * rPS1(_inst.FC);
|
double p0 = rPS0(_inst.FA) * rPS1(_inst.FC);
|
||||||
double p1 = rPS1(_inst.FA) * rPS1(_inst.FC);
|
double p1 = rPS1(_inst.FA) * rPS1(_inst.FC);
|
||||||
rPS0(_inst.FD) = p0;
|
rPS0(_inst.FD) = p0;
|
||||||
rPS1(_inst.FD) = p1;
|
rPS1(_inst.FD) = p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_madds0(UGeckoInstruction _inst)
|
void ps_madds0(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double p0 = (rPS0(_inst.FA) * rPS0(_inst.FC)) + rPS0(_inst.FB);
|
double p0 = (rPS0(_inst.FA) * rPS0(_inst.FC)) + rPS0(_inst.FB);
|
||||||
double p1 = (rPS1(_inst.FA) * rPS0(_inst.FC)) + rPS1(_inst.FB);
|
double p1 = (rPS1(_inst.FA) * rPS0(_inst.FC)) + rPS1(_inst.FB);
|
||||||
rPS0(_inst.FD) = p0;
|
rPS0(_inst.FD) = p0;
|
||||||
rPS1(_inst.FD) = p1;
|
rPS1(_inst.FD) = p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_madds1(UGeckoInstruction _inst)
|
void ps_madds1(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double p0 = (rPS0(_inst.FA) * rPS1(_inst.FC)) + rPS0(_inst.FB);
|
double p0 = (rPS0(_inst.FA) * rPS1(_inst.FC)) + rPS0(_inst.FB);
|
||||||
double p1 = (rPS1(_inst.FA) * rPS1(_inst.FC)) + rPS1(_inst.FB);
|
double p1 = (rPS1(_inst.FA) * rPS1(_inst.FC)) + rPS1(_inst.FB);
|
||||||
rPS0(_inst.FD) = p0;
|
rPS0(_inst.FD) = p0;
|
||||||
rPS1(_inst.FD) = p1;
|
rPS1(_inst.FD) = p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_cmpu0(UGeckoInstruction _inst)
|
void ps_cmpu0(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double fa = rPS0(_inst.FA);
|
double fa = rPS0(_inst.FA);
|
||||||
double fb = rPS0(_inst.FB);
|
double fb = rPS0(_inst.FB);
|
||||||
int compareResult;
|
int compareResult;
|
||||||
if (fa < fb) compareResult = 8;
|
if (fa < fb) compareResult = 8;
|
||||||
else if (fa > fb) compareResult = 4;
|
else if (fa > fb) compareResult = 4;
|
||||||
else compareResult = 2;
|
else compareResult = 2;
|
||||||
SetCRField(_inst.CRFD, compareResult);
|
SetCRField(_inst.CRFD, compareResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_cmpo0(UGeckoInstruction _inst)
|
void ps_cmpo0(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
// for now HACK
|
// for now HACK
|
||||||
ps_cmpu0(_inst);
|
ps_cmpu0(_inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_cmpu1(UGeckoInstruction _inst)
|
void ps_cmpu1(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double fa = rPS1(_inst.FA);
|
double fa = rPS1(_inst.FA);
|
||||||
double fb = rPS1(_inst.FB);
|
double fb = rPS1(_inst.FB);
|
||||||
int compareResult;
|
int compareResult;
|
||||||
if (fa < fb) compareResult = 8;
|
if (fa < fb) compareResult = 8;
|
||||||
else if (fa > fb) compareResult = 4;
|
else if (fa > fb) compareResult = 4;
|
||||||
else compareResult = 2;
|
else compareResult = 2;
|
||||||
|
|
||||||
SetCRField(_inst.CRFD, compareResult);
|
SetCRField(_inst.CRFD, compareResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ps_cmpo1(UGeckoInstruction _inst)
|
void ps_cmpo1(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
// for now HACK
|
// for now HACK
|
||||||
ps_cmpu1(_inst);
|
ps_cmpu1(_inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
// dcbz_l
|
// dcbz_l
|
||||||
// TODO(ector) check docs
|
// TODO(ector) check docs
|
||||||
void dcbz_l(UGeckoInstruction _inst)
|
void dcbz_l(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
// This is supposed to allocate a cache line in the locked cache. Not entirely sure how
|
// This is supposed to allocate a cache line in the locked cache. Not entirely sure how
|
||||||
// this is visible to the rest of the world. For now, we ignore it.
|
// this is visible to the rest of the world. For now, we ignore it.
|
||||||
/*
|
/*
|
||||||
addr_t ea = Helper_Get_EA(_inst);
|
addr_t ea = Helper_Get_EA(_inst);
|
||||||
|
|
||||||
u32 blockStart = ea & (~(CACHEBLOCKSIZE-1));
|
u32 blockStart = ea & (~(CACHEBLOCKSIZE-1));
|
||||||
u32 blockEnd = blockStart + CACHEBLOCKSIZE;
|
u32 blockEnd = blockStart + CACHEBLOCKSIZE;
|
||||||
|
|
||||||
//FAKE: clear memory instead of clearing the cache block
|
//FAKE: clear memory instead of clearing the cache block
|
||||||
for (int i=blockStart; i<blockEnd; i+=4)
|
for (int i=blockStart; i<blockEnd; i+=4)
|
||||||
Memory::Write_U32(0,i);
|
Memory::Write_U32(0,i);
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,420 +1,420 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "x64Emitter.h"
|
#include "x64Emitter.h"
|
||||||
#include "ABI.h"
|
#include "ABI.h"
|
||||||
#include "Thunk.h"
|
#include "Thunk.h"
|
||||||
#include "../../HLE/HLE.h"
|
#include "../../HLE/HLE.h"
|
||||||
#include "../../Core.h"
|
#include "../../Core.h"
|
||||||
#include "../../PatchEngine.h"
|
#include "../../PatchEngine.h"
|
||||||
#include "../../CoreTiming.h"
|
#include "../../CoreTiming.h"
|
||||||
#include "../PowerPC.h"
|
#include "../PowerPC.h"
|
||||||
#include "../Profiler.h"
|
#include "../Profiler.h"
|
||||||
#include "../PPCTables.h"
|
#include "../PPCTables.h"
|
||||||
#include "../PPCAnalyst.h"
|
#include "../PPCAnalyst.h"
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
#include "../../HW/GPFifo.h"
|
#include "../../HW/GPFifo.h"
|
||||||
#include "Jit.h"
|
#include "Jit.h"
|
||||||
#include "JitAsm.h"
|
#include "JitAsm.h"
|
||||||
#include "JitCache.h"
|
#include "JitCache.h"
|
||||||
#include "JitRegCache.h"
|
#include "JitRegCache.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
using namespace PowerPC;
|
using namespace PowerPC;
|
||||||
|
|
||||||
extern int blocksExecuted;
|
extern int blocksExecuted;
|
||||||
|
|
||||||
// Dolphin's PowerPC->x86 JIT dynamic recompiler
|
// Dolphin's PowerPC->x86 JIT dynamic recompiler
|
||||||
// All code by ector (hrydgard)
|
// All code by ector (hrydgard)
|
||||||
// Features:
|
// Features:
|
||||||
// * x86 & x64 support, lots of shared code.
|
// * x86 & x64 support, lots of shared code.
|
||||||
// * Basic block linking
|
// * Basic block linking
|
||||||
// * Fast dispatcher
|
// * Fast dispatcher
|
||||||
|
|
||||||
// Unfeatures:
|
// Unfeatures:
|
||||||
// * Does not recompile all instructions. Often falls back to inserting a CALL to the corresponding JIT function.
|
// * Does not recompile all instructions. Often falls back to inserting a CALL to the corresponding JIT function.
|
||||||
|
|
||||||
|
|
||||||
// Various notes below
|
// Various notes below
|
||||||
|
|
||||||
// Register allocation
|
// Register allocation
|
||||||
// RAX - Generic quicktemp register
|
// RAX - Generic quicktemp register
|
||||||
// RBX - point to base of memory map
|
// RBX - point to base of memory map
|
||||||
// RSI RDI R12 R13 R14 R15 - free for allocation
|
// RSI RDI R12 R13 R14 R15 - free for allocation
|
||||||
// RCX RDX R8 R9 R10 R11 - allocate in emergencies. These need to be flushed before functions are called.
|
// RCX RDX R8 R9 R10 R11 - allocate in emergencies. These need to be flushed before functions are called.
|
||||||
// RSP - stack pointer, do not generally use, very dangerous
|
// RSP - stack pointer, do not generally use, very dangerous
|
||||||
// RBP - ?
|
// RBP - ?
|
||||||
|
|
||||||
// IMPORTANT:
|
// IMPORTANT:
|
||||||
// Make sure that all generated code and all emulator state sits under the 2GB boundary so that
|
// Make sure that all generated code and all emulator state sits under the 2GB boundary so that
|
||||||
// RIP addressing can be used easily. Windows will always allocate static code under the 2GB boundary.
|
// RIP addressing can be used easily. Windows will always allocate static code under the 2GB boundary.
|
||||||
// Also make sure to use VirtualAlloc and specify EXECUTE permission.
|
// Also make sure to use VirtualAlloc and specify EXECUTE permission.
|
||||||
|
|
||||||
// Open questions
|
// Open questions
|
||||||
// * Should there be any statically allocated registers? r3, r4, r5, r8, r0 come to mind.. maybe sp
|
// * Should there be any statically allocated registers? r3, r4, r5, r8, r0 come to mind.. maybe sp
|
||||||
// * Does it make sense to finish off the remaining non-jitted instructions? Seems we are hitting diminishing returns.
|
// * Does it make sense to finish off the remaining non-jitted instructions? Seems we are hitting diminishing returns.
|
||||||
// * Why is the FPU exception handling not working 100%? Several games still get corrupted floating point state.
|
// * Why is the FPU exception handling not working 100%? Several games still get corrupted floating point state.
|
||||||
// This can even be seen in one homebrew Wii demo - RayTracer.elf
|
// This can even be seen in one homebrew Wii demo - RayTracer.elf
|
||||||
|
|
||||||
// Other considerations
|
// Other considerations
|
||||||
|
|
||||||
//Many instructions have shorter forms for EAX. However, I believe their performance boost
|
//Many instructions have shorter forms for EAX. However, I believe their performance boost
|
||||||
//will be as small to be negligble, so I haven't dirtied up the code with that. AMD recommends it in their
|
//will be as small to be negligble, so I haven't dirtied up the code with that. AMD recommends it in their
|
||||||
//optimization manuals, though.
|
//optimization manuals, though.
|
||||||
|
|
||||||
// We support block linking. Reserve space at the exits of every block for a full 5-byte jmp. Save 16-bit offsets
|
// We support block linking. Reserve space at the exits of every block for a full 5-byte jmp. Save 16-bit offsets
|
||||||
// from the starts of each block, marking the exits so that they can be nicely patched at any time.
|
// from the starts of each block, marking the exits so that they can be nicely patched at any time.
|
||||||
|
|
||||||
// * Blocks do NOT use call/ret, they only jmp to each other and to the dispatcher when necessary.
|
// * Blocks do NOT use call/ret, they only jmp to each other and to the dispatcher when necessary.
|
||||||
|
|
||||||
// All blocks that can be precompiled will be precompiled. Code will be memory protected - any write will mark
|
// All blocks that can be precompiled will be precompiled. Code will be memory protected - any write will mark
|
||||||
// the region as non-compilable, and all links to the page will be torn out and replaced with dispatcher jmps.
|
// the region as non-compilable, and all links to the page will be torn out and replaced with dispatcher jmps.
|
||||||
|
|
||||||
// Alternatively, icbi instruction SHOULD mark where we can't compile
|
// Alternatively, icbi instruction SHOULD mark where we can't compile
|
||||||
|
|
||||||
// Seldom-happening events will be handled by adding a decrement of a counter to all blr instructions (which are
|
// Seldom-happening events will be handled by adding a decrement of a counter to all blr instructions (which are
|
||||||
// expensive anyway since we need to return to dispatcher, except when they can be predicted).
|
// expensive anyway since we need to return to dispatcher, except when they can be predicted).
|
||||||
|
|
||||||
// TODO: SERIOUS synchronization problem with the video plugin setting tokens and breakpoints in dual core mode!!!
|
// TODO: SERIOUS synchronization problem with the video plugin setting tokens and breakpoints in dual core mode!!!
|
||||||
// Somewhat fixed by disabling idle skipping when certain interrupts are enabled
|
// Somewhat fixed by disabling idle skipping when certain interrupts are enabled
|
||||||
// This is no permantent reliable fix
|
// This is no permantent reliable fix
|
||||||
// TODO: Zeldas go whacko when you hang the gfx thread
|
// TODO: Zeldas go whacko when you hang the gfx thread
|
||||||
|
|
||||||
// Idea - Accurate exception handling
|
// Idea - Accurate exception handling
|
||||||
// Compute register state at a certain instruction by running the JIT in "dry mode", and stopping at the right place.
|
// Compute register state at a certain instruction by running the JIT in "dry mode", and stopping at the right place.
|
||||||
// Not likely to be done :P
|
// Not likely to be done :P
|
||||||
|
|
||||||
|
|
||||||
// Optimization Ideas -
|
// Optimization Ideas -
|
||||||
/*
|
/*
|
||||||
* Assume SP is in main RAM (in Wii mode too?) - partly done
|
* Assume SP is in main RAM (in Wii mode too?) - partly done
|
||||||
* Assume all floating point loads and double precision loads+stores are to/from main ram
|
* Assume all floating point loads and double precision loads+stores are to/from main ram
|
||||||
(single precision can be used in write gather pipe, specialized fast check added)
|
(single precision can be used in write gather pipe, specialized fast check added)
|
||||||
* AMD only - use movaps instead of movapd when loading ps from memory?
|
* AMD only - use movaps instead of movapd when loading ps from memory?
|
||||||
* HLE functions like floorf, sin, memcpy, etc - they can be much faster
|
* HLE functions like floorf, sin, memcpy, etc - they can be much faster
|
||||||
* ABI optimizations - drop F0-F13 on blr, for example. Watch out for context switching.
|
* ABI optimizations - drop F0-F13 on blr, for example. Watch out for context switching.
|
||||||
CR2-CR4 are non-volatile, rest of CR is volatile -> dropped on blr.
|
CR2-CR4 are non-volatile, rest of CR is volatile -> dropped on blr.
|
||||||
R5-R12 are volatile -> dropped on blr.
|
R5-R12 are volatile -> dropped on blr.
|
||||||
* classic inlining across calls.
|
* classic inlining across calls.
|
||||||
|
|
||||||
Metroid wants
|
Metroid wants
|
||||||
subc
|
subc
|
||||||
subfe
|
subfe
|
||||||
|
|
||||||
Low hanging fruit:
|
Low hanging fruit:
|
||||||
stfd -- guaranteed in memory
|
stfd -- guaranteed in memory
|
||||||
cmpl
|
cmpl
|
||||||
mulli
|
mulli
|
||||||
stfs
|
stfs
|
||||||
stwu
|
stwu
|
||||||
lb/stzx
|
lb/stzx
|
||||||
|
|
||||||
bcx - optimize!
|
bcx - optimize!
|
||||||
bcctr
|
bcctr
|
||||||
stfs
|
stfs
|
||||||
psq_st
|
psq_st
|
||||||
addx
|
addx
|
||||||
orx
|
orx
|
||||||
rlwimix
|
rlwimix
|
||||||
fcmpo
|
fcmpo
|
||||||
DSP_UpdateARAMDMA
|
DSP_UpdateARAMDMA
|
||||||
lfd
|
lfd
|
||||||
stwu
|
stwu
|
||||||
cntlzwx
|
cntlzwx
|
||||||
bcctrx
|
bcctrx
|
||||||
WriteBigEData
|
WriteBigEData
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
lha
|
lha
|
||||||
srawx
|
srawx
|
||||||
addic_rc
|
addic_rc
|
||||||
addex
|
addex
|
||||||
subfcx
|
subfcx
|
||||||
subfex
|
subfex
|
||||||
|
|
||||||
fmaddx
|
fmaddx
|
||||||
fmulx
|
fmulx
|
||||||
faddx
|
faddx
|
||||||
fnegx
|
fnegx
|
||||||
frspx
|
frspx
|
||||||
frsqrtex
|
frsqrtex
|
||||||
ps_sum0
|
ps_sum0
|
||||||
ps_muls0
|
ps_muls0
|
||||||
ps_adds1
|
ps_adds1
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
namespace CPUCompare
|
namespace CPUCompare
|
||||||
{
|
{
|
||||||
extern u32 m_BlockStart;
|
extern u32 m_BlockStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace Jit64
|
namespace Jit64
|
||||||
{
|
{
|
||||||
JitState js;
|
JitState js;
|
||||||
JitOptions jo;
|
JitOptions jo;
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
jo.optimizeStack = true;
|
jo.optimizeStack = true;
|
||||||
jo.enableBlocklink = true; // Speed boost, but not 100% safe
|
jo.enableBlocklink = true; // Speed boost, but not 100% safe
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
jo.enableFastMem = Core::GetStartupParameter().bUseFastMem;
|
jo.enableFastMem = Core::GetStartupParameter().bUseFastMem;
|
||||||
#else
|
#else
|
||||||
jo.enableFastMem = false;
|
jo.enableFastMem = false;
|
||||||
#endif
|
#endif
|
||||||
jo.assumeFPLoadFromMem = true;
|
jo.assumeFPLoadFromMem = true;
|
||||||
jo.fpAccurateFlags = true;
|
jo.fpAccurateFlags = true;
|
||||||
jo.optimizeGatherPipe = true;
|
jo.optimizeGatherPipe = true;
|
||||||
jo.interpretFPU = false;
|
jo.interpretFPU = false;
|
||||||
jo.fastInterrupts = false;
|
jo.fastInterrupts = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteCallInterpreter(UGeckoInstruction _inst)
|
void WriteCallInterpreter(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush(FLUSH_ALL);
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush(FLUSH_ALL);
|
||||||
if (js.isLastInstruction)
|
if (js.isLastInstruction)
|
||||||
{
|
{
|
||||||
MOV(32, M(&PC), Imm32(js.compilerPC));
|
MOV(32, M(&PC), Imm32(js.compilerPC));
|
||||||
MOV(32, M(&NPC), Imm32(js.compilerPC + 4));
|
MOV(32, M(&NPC), Imm32(js.compilerPC + 4));
|
||||||
}
|
}
|
||||||
Interpreter::_interpreterInstruction instr = GetInterpreterOp(_inst);
|
Interpreter::_interpreterInstruction instr = GetInterpreterOp(_inst);
|
||||||
ABI_CallFunctionC((void*)instr, _inst.hex);
|
ABI_CallFunctionC((void*)instr, _inst.hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Default(UGeckoInstruction _inst)
|
void Default(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
WriteCallInterpreter(_inst.hex);
|
WriteCallInterpreter(_inst.hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HLEFunction(UGeckoInstruction _inst)
|
void HLEFunction(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush(FLUSH_ALL);
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush(FLUSH_ALL);
|
||||||
ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex);
|
ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex);
|
||||||
MOV(32, R(EAX), M(&NPC));
|
MOV(32, R(EAX), M(&NPC));
|
||||||
WriteExitDestInEAX(0);
|
WriteExitDestInEAX(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoNothing(UGeckoInstruction _inst)
|
void DoNothing(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
// Yup, just don't do anything.
|
// Yup, just don't do anything.
|
||||||
}
|
}
|
||||||
|
|
||||||
static const bool ImHereDebug = false;
|
static const bool ImHereDebug = false;
|
||||||
static const bool ImHereLog = false;
|
static const bool ImHereLog = false;
|
||||||
static std::map<u32, int> been_here;
|
static std::map<u32, int> been_here;
|
||||||
|
|
||||||
void ImHere()
|
void ImHere()
|
||||||
{
|
{
|
||||||
static FILE *f = 0;
|
static FILE *f = 0;
|
||||||
if (ImHereLog) {
|
if (ImHereLog) {
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
f = fopen("log64.txt", "w");
|
f = fopen("log64.txt", "w");
|
||||||
#else
|
#else
|
||||||
f = fopen("log32.txt", "w");
|
f = fopen("log32.txt", "w");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
fprintf(f, "%08x\n", PC);
|
fprintf(f, "%08x\n", PC);
|
||||||
}
|
}
|
||||||
if (been_here.find(PC) != been_here.end()) {
|
if (been_here.find(PC) != been_here.end()) {
|
||||||
been_here.find(PC)->second++;
|
been_here.find(PC)->second++;
|
||||||
if ((been_here.find(PC)->second) & 1023)
|
if ((been_here.find(PC)->second) & 1023)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR);
|
LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR);
|
||||||
printf("I'm here - PC = %08x , LR = %08x", PC, LR);
|
printf("I'm here - PC = %08x , LR = %08x", PC, LR);
|
||||||
been_here[PC] = 1;
|
been_here[PC] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cleanup()
|
void Cleanup()
|
||||||
{
|
{
|
||||||
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0)
|
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0)
|
||||||
CALL((void *)&GPFifo::CheckGatherPipe);
|
CALL((void *)&GPFifo::CheckGatherPipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteExit(u32 destination, int exit_num)
|
void WriteExit(u32 destination, int exit_num)
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||||
|
|
||||||
//If nobody has taken care of this yet (this can be removed when all branches are done)
|
//If nobody has taken care of this yet (this can be removed when all branches are done)
|
||||||
JitBlock *b = js.curBlock;
|
JitBlock *b = js.curBlock;
|
||||||
b->exitAddress[exit_num] = destination;
|
b->exitAddress[exit_num] = destination;
|
||||||
b->exitPtrs[exit_num] = GetWritableCodePtr();
|
b->exitPtrs[exit_num] = GetWritableCodePtr();
|
||||||
|
|
||||||
// Link opportunity!
|
// Link opportunity!
|
||||||
int block = GetBlockNumberFromAddress(destination);
|
int block = GetBlockNumberFromAddress(destination);
|
||||||
if (block >= 0 && jo.enableBlocklink)
|
if (block >= 0 && jo.enableBlocklink)
|
||||||
{
|
{
|
||||||
// It exists! Joy of joy!
|
// It exists! Joy of joy!
|
||||||
JMP(GetBlock(block)->checkedEntry, true);
|
JMP(GetBlock(block)->checkedEntry, true);
|
||||||
b->linkStatus[exit_num] = true;
|
b->linkStatus[exit_num] = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MOV(32, M(&PC), Imm32(destination));
|
MOV(32, M(&PC), Imm32(destination));
|
||||||
JMP(Asm::dispatcher, true);
|
JMP(Asm::dispatcher, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteExitDestInEAX(int exit_num)
|
void WriteExitDestInEAX(int exit_num)
|
||||||
{
|
{
|
||||||
MOV(32, M(&PC), R(EAX));
|
MOV(32, M(&PC), R(EAX));
|
||||||
Cleanup();
|
Cleanup();
|
||||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||||
JMP(Asm::dispatcher, true);
|
JMP(Asm::dispatcher, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteRfiExitDestInEAX()
|
void WriteRfiExitDestInEAX()
|
||||||
{
|
{
|
||||||
MOV(32, M(&PC), R(EAX));
|
MOV(32, M(&PC), R(EAX));
|
||||||
Cleanup();
|
Cleanup();
|
||||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||||
JMP(Asm::testExceptions, true);
|
JMP(Asm::testExceptions, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteExceptionExit(u32 exception)
|
void WriteExceptionExit(u32 exception)
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(exception));
|
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(exception));
|
||||||
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
|
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
|
||||||
JMP(Asm::testExceptions, true);
|
JMP(Asm::testExceptions, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8* DoJit(u32 emaddress, JitBlock &b)
|
const u8* DoJit(u32 emaddress, JitBlock &b)
|
||||||
{
|
{
|
||||||
if (emaddress == 0)
|
if (emaddress == 0)
|
||||||
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
|
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
|
||||||
|
|
||||||
u32 size;
|
u32 size;
|
||||||
js.isLastInstruction = false;
|
js.isLastInstruction = false;
|
||||||
js.blockStart = emaddress;
|
js.blockStart = emaddress;
|
||||||
js.fifoBytesThisBlock = 0;
|
js.fifoBytesThisBlock = 0;
|
||||||
js.curBlock = &b;
|
js.curBlock = &b;
|
||||||
js.blockSetsQuantizers = false;
|
js.blockSetsQuantizers = false;
|
||||||
js.block_flags = 0;
|
js.block_flags = 0;
|
||||||
|
|
||||||
//Analyze the block, collect all instructions it is made of (including inlining,
|
//Analyze the block, collect all instructions it is made of (including inlining,
|
||||||
//if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
|
//if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
|
||||||
PPCAnalyst::CodeOp *ops = PPCAnalyst::Flatten(emaddress, size, js.st, js.gpa, js.fpa);
|
PPCAnalyst::CodeOp *ops = PPCAnalyst::Flatten(emaddress, size, js.st, js.gpa, js.fpa);
|
||||||
const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr
|
const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr
|
||||||
b.checkedEntry = start;
|
b.checkedEntry = start;
|
||||||
b.runCount = 0;
|
b.runCount = 0;
|
||||||
|
|
||||||
// Downcount flag check. The last block decremented downcounter, and the flag should still be available.
|
// Downcount flag check. The last block decremented downcounter, and the flag should still be available.
|
||||||
FixupBranch skip = J_CC(CC_NBE);
|
FixupBranch skip = J_CC(CC_NBE);
|
||||||
MOV(32, M(&PC), Imm32(js.blockStart));
|
MOV(32, M(&PC), Imm32(js.blockStart));
|
||||||
JMP(Asm::doTiming, true); // downcount hit zero - go doTiming.
|
JMP(Asm::doTiming, true); // downcount hit zero - go doTiming.
|
||||||
SetJumpTarget(skip);
|
SetJumpTarget(skip);
|
||||||
|
|
||||||
const u8 *normalEntry = GetCodePtr();
|
const u8 *normalEntry = GetCodePtr();
|
||||||
if (ImHereDebug) CALL((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful
|
if (ImHereDebug) CALL((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful
|
||||||
|
|
||||||
if (js.fpa.any)
|
if (js.fpa.any)
|
||||||
{
|
{
|
||||||
//This block uses FPU - needs to add FP exception bailout
|
//This block uses FPU - needs to add FP exception bailout
|
||||||
TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); //Test FP enabled bit
|
TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); //Test FP enabled bit
|
||||||
FixupBranch b1 = J_CC(CC_NZ);
|
FixupBranch b1 = J_CC(CC_NZ);
|
||||||
MOV(32, M(&PC), Imm32(js.blockStart));
|
MOV(32, M(&PC), Imm32(js.blockStart));
|
||||||
JMP(Asm::fpException, true);
|
JMP(Asm::fpException, true);
|
||||||
SetJumpTarget(b1);
|
SetJumpTarget(b1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false && jo.fastInterrupts)
|
if (false && jo.fastInterrupts)
|
||||||
{
|
{
|
||||||
// This does NOT yet work.
|
// This does NOT yet work.
|
||||||
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
|
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
|
||||||
FixupBranch b1 = J_CC(CC_Z);
|
FixupBranch b1 = J_CC(CC_Z);
|
||||||
MOV(32, M(&PC), Imm32(js.blockStart));
|
MOV(32, M(&PC), Imm32(js.blockStart));
|
||||||
JMP(Asm::testExceptions, true);
|
JMP(Asm::testExceptions, true);
|
||||||
SetJumpTarget(b1);
|
SetJumpTarget(b1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conditionally add profiling code.
|
// Conditionally add profiling code.
|
||||||
if (Profiler::g_ProfileBlocks) {
|
if (Profiler::g_ProfileBlocks) {
|
||||||
ADD(32, M(&b.runCount), Imm8(1));
|
ADD(32, M(&b.runCount), Imm8(1));
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
b.ticCounter.QuadPart = 0;
|
b.ticCounter.QuadPart = 0;
|
||||||
b.ticStart.QuadPart = 0;
|
b.ticStart.QuadPart = 0;
|
||||||
b.ticStop.QuadPart = 0;
|
b.ticStop.QuadPart = 0;
|
||||||
#else
|
#else
|
||||||
//TODO
|
//TODO
|
||||||
#endif
|
#endif
|
||||||
// get start tic
|
// get start tic
|
||||||
PROFILER_QUERY_PERFORMACE_COUNTER(&b.ticStart);
|
PROFILER_QUERY_PERFORMACE_COUNTER(&b.ticStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Start up the register allocators
|
//Start up the register allocators
|
||||||
//They use the information in gpa/fpa to preload commonly used registers.
|
//They use the information in gpa/fpa to preload commonly used registers.
|
||||||
gpr.Start(js.gpa);
|
gpr.Start(js.gpa);
|
||||||
fpr.Start(js.fpa);
|
fpr.Start(js.fpa);
|
||||||
|
|
||||||
js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(emaddress);
|
js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(emaddress);
|
||||||
js.blockSize = size;
|
js.blockSize = size;
|
||||||
// Translate instructions
|
// Translate instructions
|
||||||
for (int i = 0; i < (int)size; i++)
|
for (int i = 0; i < (int)size; i++)
|
||||||
{
|
{
|
||||||
// gpr.Flush(FLUSH_ALL);
|
// gpr.Flush(FLUSH_ALL);
|
||||||
// if (PPCTables::UsesFPU(_inst))
|
// if (PPCTables::UsesFPU(_inst))
|
||||||
// fpr.Flush(FLUSH_ALL);
|
// fpr.Flush(FLUSH_ALL);
|
||||||
js.compilerPC = ops[i].address;
|
js.compilerPC = ops[i].address;
|
||||||
js.op = &ops[i];
|
js.op = &ops[i];
|
||||||
js.instructionNumber = i;
|
js.instructionNumber = i;
|
||||||
if (i == (int)size - 1) {
|
if (i == (int)size - 1) {
|
||||||
js.isLastInstruction = true;
|
js.isLastInstruction = true;
|
||||||
if (Profiler::g_ProfileBlocks) {
|
if (Profiler::g_ProfileBlocks) {
|
||||||
// CAUTION!!! push on stack regs you use, do your stuff, then pop
|
// CAUTION!!! push on stack regs you use, do your stuff, then pop
|
||||||
PROFILER_VPUSH;
|
PROFILER_VPUSH;
|
||||||
// get end tic
|
// get end tic
|
||||||
PROFILER_QUERY_PERFORMACE_COUNTER(&b.ticStop);
|
PROFILER_QUERY_PERFORMACE_COUNTER(&b.ticStop);
|
||||||
// tic counter += (end tic - start tic)
|
// tic counter += (end tic - start tic)
|
||||||
PROFILER_ADD_DIFF_LARGE_INTEGER(&b.ticCounter, &b.ticStop, &b.ticStart);
|
PROFILER_ADD_DIFF_LARGE_INTEGER(&b.ticCounter, &b.ticStop, &b.ticStart);
|
||||||
PROFILER_VPOP;
|
PROFILER_VPOP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// const GekkoOpInfo *info = GetOpInfo();
|
// const GekkoOpInfo *info = GetOpInfo();
|
||||||
if (jo.interpretFPU && PPCTables::UsesFPU(ops[i].inst))
|
if (jo.interpretFPU && PPCTables::UsesFPU(ops[i].inst))
|
||||||
Default(ops[i].inst);
|
Default(ops[i].inst);
|
||||||
else
|
else
|
||||||
PPCTables::CompileInstruction(ops[i].inst);
|
PPCTables::CompileInstruction(ops[i].inst);
|
||||||
|
|
||||||
gpr.SanityCheck();
|
gpr.SanityCheck();
|
||||||
fpr.SanityCheck();
|
fpr.SanityCheck();
|
||||||
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32)
|
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32)
|
||||||
{
|
{
|
||||||
js.fifoBytesThisBlock -= 32;
|
js.fifoBytesThisBlock -= 32;
|
||||||
CALL(ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0));
|
CALL(ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
js.compilerPC += 4;
|
js.compilerPC += 4;
|
||||||
|
|
||||||
b.flags = js.block_flags;
|
b.flags = js.block_flags;
|
||||||
b.codeSize = (u32)(GetCodePtr() - start);
|
b.codeSize = (u32)(GetCodePtr() - start);
|
||||||
b.originalSize = js.compilerPC - emaddress;
|
b.originalSize = js.compilerPC - emaddress;
|
||||||
return normalEntry;
|
return normalEntry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,374 +1,374 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "ABI.h"
|
#include "ABI.h"
|
||||||
#include "x64Emitter.h"
|
#include "x64Emitter.h"
|
||||||
|
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
|
|
||||||
#include "../PowerPC.h"
|
#include "../PowerPC.h"
|
||||||
#include "../../CoreTiming.h"
|
#include "../../CoreTiming.h"
|
||||||
#include "MemoryUtil.h"
|
#include "MemoryUtil.h"
|
||||||
|
|
||||||
#include "ABI.h"
|
#include "ABI.h"
|
||||||
#include "Jit.h"
|
#include "Jit.h"
|
||||||
#include "JitCache.h"
|
#include "JitCache.h"
|
||||||
|
|
||||||
#include "../../HW/CPUCompare.h"
|
#include "../../HW/CPUCompare.h"
|
||||||
#include "../../HW/GPFifo.h"
|
#include "../../HW/GPFifo.h"
|
||||||
#include "../../Core.h"
|
#include "../../Core.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
int blocksExecuted;
|
int blocksExecuted;
|
||||||
|
|
||||||
namespace Jit64
|
namespace Jit64
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace Asm
|
namespace Asm
|
||||||
{
|
{
|
||||||
const u8 *enterCode;
|
const u8 *enterCode;
|
||||||
const u8 *testExceptions;
|
const u8 *testExceptions;
|
||||||
const u8 *fpException;
|
const u8 *fpException;
|
||||||
const u8 *doTiming;
|
const u8 *doTiming;
|
||||||
const u8 *dispatcher;
|
const u8 *dispatcher;
|
||||||
const u8 *dispatcherNoCheck;
|
const u8 *dispatcherNoCheck;
|
||||||
const u8 *dispatcherPcInEAX;
|
const u8 *dispatcherPcInEAX;
|
||||||
const u8 *computeRc;
|
const u8 *computeRc;
|
||||||
const u8 *computeRcFp;
|
const u8 *computeRcFp;
|
||||||
|
|
||||||
const u8 *fifoDirectWrite8;
|
const u8 *fifoDirectWrite8;
|
||||||
const u8 *fifoDirectWrite16;
|
const u8 *fifoDirectWrite16;
|
||||||
const u8 *fifoDirectWrite32;
|
const u8 *fifoDirectWrite32;
|
||||||
const u8 *fifoDirectWriteFloat;
|
const u8 *fifoDirectWriteFloat;
|
||||||
const u8 *fifoDirectWriteXmm64;
|
const u8 *fifoDirectWriteXmm64;
|
||||||
|
|
||||||
bool compareEnabled = false;
|
bool compareEnabled = false;
|
||||||
|
|
||||||
//TODO - make an option
|
//TODO - make an option
|
||||||
//#if _DEBUG
|
//#if _DEBUG
|
||||||
static bool enableDebug = false;
|
static bool enableDebug = false;
|
||||||
//#else
|
//#else
|
||||||
// bool enableDebug = false;
|
// bool enableDebug = false;
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
static bool enableStatistics = false;
|
static bool enableStatistics = false;
|
||||||
|
|
||||||
//GLOBAL STATIC ALLOCATIONS x86
|
//GLOBAL STATIC ALLOCATIONS x86
|
||||||
//EAX - ubiquitous scratch register - EVERYBODY scratches this
|
//EAX - ubiquitous scratch register - EVERYBODY scratches this
|
||||||
|
|
||||||
//GLOBAL STATIC ALLOCATIONS x64
|
//GLOBAL STATIC ALLOCATIONS x64
|
||||||
//EAX - ubiquitous scratch register - EVERYBODY scratches this
|
//EAX - ubiquitous scratch register - EVERYBODY scratches this
|
||||||
//RBX - Base pointer of memory
|
//RBX - Base pointer of memory
|
||||||
//R15 - Pointer to array of block pointers
|
//R15 - Pointer to array of block pointers
|
||||||
|
|
||||||
|
|
||||||
// PLAN: no more block numbers - crazy opcodes just contain offset within
|
// PLAN: no more block numbers - crazy opcodes just contain offset within
|
||||||
// dynarec buffer
|
// dynarec buffer
|
||||||
// At this offset - 4, there is an int specifying the block number.
|
// At this offset - 4, there is an int specifying the block number.
|
||||||
|
|
||||||
|
|
||||||
void GenerateCommon();
|
void GenerateCommon();
|
||||||
|
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
void Generate()
|
void Generate()
|
||||||
{
|
{
|
||||||
enterCode = AlignCode16();
|
enterCode = AlignCode16();
|
||||||
PUSH(EBP);
|
PUSH(EBP);
|
||||||
PUSH(EBX);
|
PUSH(EBX);
|
||||||
PUSH(ESI);
|
PUSH(ESI);
|
||||||
PUSH(EDI);
|
PUSH(EDI);
|
||||||
|
|
||||||
//MOV(32, R(EBX), Imm32((u32)&Memory::base));
|
//MOV(32, R(EBX), Imm32((u32)&Memory::base));
|
||||||
const u8 *outerLoop = GetCodePtr();
|
const u8 *outerLoop = GetCodePtr();
|
||||||
CALL(reinterpret_cast<void *>(&CoreTiming::Advance));
|
CALL(reinterpret_cast<void *>(&CoreTiming::Advance));
|
||||||
FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time
|
FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time
|
||||||
|
|
||||||
dispatcher = GetCodePtr();
|
dispatcher = GetCodePtr();
|
||||||
//This is the place for CPUCompare!
|
//This is the place for CPUCompare!
|
||||||
|
|
||||||
//The result of slice decrementation should be in flags if somebody jumped here
|
//The result of slice decrementation should be in flags if somebody jumped here
|
||||||
//Jump on negative, not carry!!!
|
//Jump on negative, not carry!!!
|
||||||
FixupBranch bail = J_CC(CC_BE);
|
FixupBranch bail = J_CC(CC_BE);
|
||||||
if (Core::bReadTrace || Core::bWriteTrace)
|
if (Core::bReadTrace || Core::bWriteTrace)
|
||||||
{
|
{
|
||||||
CALL(reinterpret_cast<void *>(&Core::SyncTrace));
|
CALL(reinterpret_cast<void *>(&Core::SyncTrace));
|
||||||
// CMP(32, R(EAX),Imm32(0));
|
// CMP(32, R(EAX),Imm32(0));
|
||||||
// bail2 = J_CC();
|
// bail2 = J_CC();
|
||||||
}
|
}
|
||||||
SetJumpTarget(skipToRealDispatch);
|
SetJumpTarget(skipToRealDispatch);
|
||||||
//TEST(32,M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
|
//TEST(32,M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
|
||||||
//FixupBranch bail2 = J_CC(CC_NZ);
|
//FixupBranch bail2 = J_CC(CC_NZ);
|
||||||
dispatcherNoCheck = GetCodePtr();
|
dispatcherNoCheck = GetCodePtr();
|
||||||
MOV(32, R(EAX), M(&PowerPC::ppcState.pc));
|
MOV(32, R(EAX), M(&PowerPC::ppcState.pc));
|
||||||
dispatcherPcInEAX = GetCodePtr();
|
dispatcherPcInEAX = GetCodePtr();
|
||||||
|
|
||||||
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
||||||
MOV(32, R(EBX), Imm32((u32)Memory::base));
|
MOV(32, R(EBX), Imm32((u32)Memory::base));
|
||||||
MOV(32, R(EAX), MComplex(EBX, EAX, SCALE_1, 0));
|
MOV(32, R(EAX), MComplex(EBX, EAX, SCALE_1, 0));
|
||||||
TEST(32, R(EAX), Imm32(0xFC));
|
TEST(32, R(EAX), Imm32(0xFC));
|
||||||
FixupBranch notfound = J_CC(CC_NZ);
|
FixupBranch notfound = J_CC(CC_NZ);
|
||||||
BSWAP(32, EAX);
|
BSWAP(32, EAX);
|
||||||
//IDEA - we have 26 bits, why not just use offsets from base of code?
|
//IDEA - we have 26 bits, why not just use offsets from base of code?
|
||||||
if (enableStatistics)
|
if (enableStatistics)
|
||||||
{
|
{
|
||||||
ADD(32, M(&blocksExecuted), Imm8(1));
|
ADD(32, M(&blocksExecuted), Imm8(1));
|
||||||
}
|
}
|
||||||
if (enableDebug)
|
if (enableDebug)
|
||||||
{
|
{
|
||||||
ADD(32, M(&PowerPC::ppcState.DebugCount), Imm8(1));
|
ADD(32, M(&PowerPC::ppcState.DebugCount), Imm8(1));
|
||||||
}
|
}
|
||||||
//grab from list and jump to it
|
//grab from list and jump to it
|
||||||
//INT3();
|
//INT3();
|
||||||
MOV(32, R(EDX), ImmPtr(GetCodePointers()));
|
MOV(32, R(EDX), ImmPtr(GetCodePointers()));
|
||||||
JMPptr(MComplex(EDX, EAX, 4, 0));
|
JMPptr(MComplex(EDX, EAX, 4, 0));
|
||||||
SetJumpTarget(notfound);
|
SetJumpTarget(notfound);
|
||||||
|
|
||||||
//Ok, no block, let's jit
|
//Ok, no block, let's jit
|
||||||
ABI_AlignStack(4);
|
ABI_AlignStack(4);
|
||||||
PUSH(32, M(&PowerPC::ppcState.pc));
|
PUSH(32, M(&PowerPC::ppcState.pc));
|
||||||
CALL(reinterpret_cast<void *>(&Jit));
|
CALL(reinterpret_cast<void *>(&Jit));
|
||||||
ABI_RestoreStack(4);
|
ABI_RestoreStack(4);
|
||||||
JMP(dispatcherNoCheck); // no point in special casing this
|
JMP(dispatcherNoCheck); // no point in special casing this
|
||||||
|
|
||||||
//FP blocks test for FPU available, jump here if false
|
//FP blocks test for FPU available, jump here if false
|
||||||
fpException = AlignCode4();
|
fpException = AlignCode4();
|
||||||
MOV(32, R(EAX), M(&PC));
|
MOV(32, R(EAX), M(&PC));
|
||||||
MOV(32, M(&NPC), R(EAX));
|
MOV(32, M(&NPC), R(EAX));
|
||||||
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
|
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
|
||||||
CALL(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
CALL(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||||
MOV(32, R(EAX), M(&NPC));
|
MOV(32, R(EAX), M(&NPC));
|
||||||
MOV(32, M(&PC), R(EAX));
|
MOV(32, M(&PC), R(EAX));
|
||||||
JMP(dispatcher);
|
JMP(dispatcher);
|
||||||
|
|
||||||
SetJumpTarget(bail);
|
SetJumpTarget(bail);
|
||||||
doTiming = GetCodePtr();
|
doTiming = GetCodePtr();
|
||||||
|
|
||||||
CALL(reinterpret_cast<void *>(&CoreTiming::Advance));
|
CALL(reinterpret_cast<void *>(&CoreTiming::Advance));
|
||||||
|
|
||||||
testExceptions = GetCodePtr();
|
testExceptions = GetCodePtr();
|
||||||
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
|
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
|
||||||
FixupBranch skipExceptions = J_CC(CC_Z);
|
FixupBranch skipExceptions = J_CC(CC_Z);
|
||||||
MOV(32, R(EAX), M(&PC));
|
MOV(32, R(EAX), M(&PC));
|
||||||
MOV(32, M(&NPC), R(EAX));
|
MOV(32, M(&NPC), R(EAX));
|
||||||
CALL(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
CALL(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||||
MOV(32, R(EAX), M(&NPC));
|
MOV(32, R(EAX), M(&NPC));
|
||||||
MOV(32, M(&PC), R(EAX));
|
MOV(32, M(&PC), R(EAX));
|
||||||
SetJumpTarget(skipExceptions);
|
SetJumpTarget(skipExceptions);
|
||||||
|
|
||||||
TEST(32, M((void*)&PowerPC::state), Imm32(0xFFFFFFFF));
|
TEST(32, M((void*)&PowerPC::state), Imm32(0xFFFFFFFF));
|
||||||
J_CC(CC_Z, outerLoop, true);
|
J_CC(CC_Z, outerLoop, true);
|
||||||
|
|
||||||
POP(EDI);
|
POP(EDI);
|
||||||
POP(ESI);
|
POP(ESI);
|
||||||
POP(EBX);
|
POP(EBX);
|
||||||
POP(EBP);
|
POP(EBP);
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
GenerateCommon();
|
GenerateCommon();
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(_M_X64)
|
#elif defined(_M_X64)
|
||||||
|
|
||||||
void Generate()
|
void Generate()
|
||||||
{
|
{
|
||||||
enterCode = AlignCode16();
|
enterCode = AlignCode16();
|
||||||
|
|
||||||
ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
||||||
|
|
||||||
MOV(64, R(RBX), Imm64((u64)Memory::base));
|
MOV(64, R(RBX), Imm64((u64)Memory::base));
|
||||||
MOV(64, R(R15), Imm64((u64)GetCodePointers())); //It's below 2GB so 32 bits are good enough
|
MOV(64, R(R15), Imm64((u64)GetCodePointers())); //It's below 2GB so 32 bits are good enough
|
||||||
const u8 *outerLoop = GetCodePtr();
|
const u8 *outerLoop = GetCodePtr();
|
||||||
|
|
||||||
CALL((void *)&CoreTiming::Advance);
|
CALL((void *)&CoreTiming::Advance);
|
||||||
FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time
|
FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time
|
||||||
|
|
||||||
dispatcher = GetCodePtr();
|
dispatcher = GetCodePtr();
|
||||||
//The result of slice decrementation should be in flags if somebody jumped here
|
//The result of slice decrementation should be in flags if somebody jumped here
|
||||||
//Jump on negative, not carry!!!
|
//Jump on negative, not carry!!!
|
||||||
FixupBranch bail = J_CC(CC_BE);
|
FixupBranch bail = J_CC(CC_BE);
|
||||||
SetJumpTarget(skipToRealDispatch);
|
SetJumpTarget(skipToRealDispatch);
|
||||||
|
|
||||||
dispatcherNoCheck = GetCodePtr();
|
dispatcherNoCheck = GetCodePtr();
|
||||||
MOV(32, R(EAX), M(&PowerPC::ppcState.pc));
|
MOV(32, R(EAX), M(&PowerPC::ppcState.pc));
|
||||||
dispatcherPcInEAX = GetCodePtr();
|
dispatcherPcInEAX = GetCodePtr();
|
||||||
MOV(32, R(EAX), MComplex(RBX, RAX, SCALE_1, 0));
|
MOV(32, R(EAX), MComplex(RBX, RAX, SCALE_1, 0));
|
||||||
TEST(32, R(EAX), Imm32(0xFC));
|
TEST(32, R(EAX), Imm32(0xFC));
|
||||||
|
|
||||||
FixupBranch notfound = J_CC(CC_NZ);
|
FixupBranch notfound = J_CC(CC_NZ);
|
||||||
BSWAP(32, EAX);
|
BSWAP(32, EAX);
|
||||||
//IDEA - we have 26 bits, why not just use offsets from base of code?
|
//IDEA - we have 26 bits, why not just use offsets from base of code?
|
||||||
if (enableStatistics)
|
if (enableStatistics)
|
||||||
{
|
{
|
||||||
ADD(32, M(&blocksExecuted), Imm8(1));
|
ADD(32, M(&blocksExecuted), Imm8(1));
|
||||||
}
|
}
|
||||||
if (enableDebug)
|
if (enableDebug)
|
||||||
{
|
{
|
||||||
ADD(32, M(&PowerPC::ppcState.DebugCount), Imm8(1));
|
ADD(32, M(&PowerPC::ppcState.DebugCount), Imm8(1));
|
||||||
}
|
}
|
||||||
//grab from list and jump to it
|
//grab from list and jump to it
|
||||||
JMPptr(MComplex(R15, RAX, 8, 0));
|
JMPptr(MComplex(R15, RAX, 8, 0));
|
||||||
SetJumpTarget(notfound);
|
SetJumpTarget(notfound);
|
||||||
|
|
||||||
//Ok, no block, let's jit
|
//Ok, no block, let's jit
|
||||||
MOV(32, R(ABI_PARAM1), M(&PowerPC::ppcState.pc));
|
MOV(32, R(ABI_PARAM1), M(&PowerPC::ppcState.pc));
|
||||||
CALL((void *)&Jit);
|
CALL((void *)&Jit);
|
||||||
JMP(dispatcherNoCheck); // no point in special casing this, not the "fast path"
|
JMP(dispatcherNoCheck); // no point in special casing this, not the "fast path"
|
||||||
|
|
||||||
//FP blocks test for FPU available, jump here if false
|
//FP blocks test for FPU available, jump here if false
|
||||||
fpException = AlignCode4();
|
fpException = AlignCode4();
|
||||||
MOV(32, R(EAX), M(&PC));
|
MOV(32, R(EAX), M(&PC));
|
||||||
MOV(32, M(&NPC), R(EAX));
|
MOV(32, M(&NPC), R(EAX));
|
||||||
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
|
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
|
||||||
CALL((void *)&PowerPC::CheckExceptions);
|
CALL((void *)&PowerPC::CheckExceptions);
|
||||||
MOV(32, R(EAX), M(&NPC));
|
MOV(32, R(EAX), M(&NPC));
|
||||||
MOV(32, M(&PC), R(EAX));
|
MOV(32, M(&PC), R(EAX));
|
||||||
JMP(dispatcherNoCheck);
|
JMP(dispatcherNoCheck);
|
||||||
|
|
||||||
SetJumpTarget(bail);
|
SetJumpTarget(bail);
|
||||||
doTiming = GetCodePtr();
|
doTiming = GetCodePtr();
|
||||||
TEST(32, M(&PC), Imm32(0xFFFFFFFF));
|
TEST(32, M(&PC), Imm32(0xFFFFFFFF));
|
||||||
FixupBranch mojs = J_CC(CC_NZ);
|
FixupBranch mojs = J_CC(CC_NZ);
|
||||||
INT3(); // if you hit this, PC == 0 - no good
|
INT3(); // if you hit this, PC == 0 - no good
|
||||||
SetJumpTarget(mojs);
|
SetJumpTarget(mojs);
|
||||||
CALL((void *)&CoreTiming::Advance);
|
CALL((void *)&CoreTiming::Advance);
|
||||||
|
|
||||||
testExceptions = GetCodePtr();
|
testExceptions = GetCodePtr();
|
||||||
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
|
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
|
||||||
FixupBranch skipExceptions = J_CC(CC_Z);
|
FixupBranch skipExceptions = J_CC(CC_Z);
|
||||||
MOV(32, R(EAX), M(&PC));
|
MOV(32, R(EAX), M(&PC));
|
||||||
MOV(32, M(&NPC), R(EAX));
|
MOV(32, M(&NPC), R(EAX));
|
||||||
CALL((void *)&PowerPC::CheckExceptions);
|
CALL((void *)&PowerPC::CheckExceptions);
|
||||||
MOV(32, R(EAX), M(&NPC));
|
MOV(32, R(EAX), M(&NPC));
|
||||||
MOV(32, M(&PC), R(EAX));
|
MOV(32, M(&PC), R(EAX));
|
||||||
SetJumpTarget(skipExceptions);
|
SetJumpTarget(skipExceptions);
|
||||||
|
|
||||||
TEST(32, M((void*)&PowerPC::state), Imm32(0xFFFFFFFF));
|
TEST(32, M((void*)&PowerPC::state), Imm32(0xFFFFFFFF));
|
||||||
J_CC(CC_Z, outerLoop, true);
|
J_CC(CC_Z, outerLoop, true);
|
||||||
|
|
||||||
//Landing pad for drec space
|
//Landing pad for drec space
|
||||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
GenerateCommon();
|
GenerateCommon();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void GenFifoWrite(int size)
|
void GenFifoWrite(int size)
|
||||||
{
|
{
|
||||||
// Assume value in ABI_PARAM1
|
// Assume value in ABI_PARAM1
|
||||||
PUSH(ESI);
|
PUSH(ESI);
|
||||||
if (size != 32)
|
if (size != 32)
|
||||||
PUSH(EDX);
|
PUSH(EDX);
|
||||||
BSWAP(size, ABI_PARAM1);
|
BSWAP(size, ABI_PARAM1);
|
||||||
MOV(32, R(EAX), Imm32((u32)(u64)GPFifo::m_gatherPipe));
|
MOV(32, R(EAX), Imm32((u32)(u64)GPFifo::m_gatherPipe));
|
||||||
MOV(32, R(ESI), M(&GPFifo::m_gatherPipeCount));
|
MOV(32, R(ESI), M(&GPFifo::m_gatherPipeCount));
|
||||||
if (size != 32) {
|
if (size != 32) {
|
||||||
MOV(32, R(EDX), R(ABI_PARAM1));
|
MOV(32, R(EDX), R(ABI_PARAM1));
|
||||||
MOV(size, MComplex(RAX, RSI, 1, 0), R(EDX));
|
MOV(size, MComplex(RAX, RSI, 1, 0), R(EDX));
|
||||||
} else {
|
} else {
|
||||||
MOV(size, MComplex(RAX, RSI, 1, 0), R(ABI_PARAM1));
|
MOV(size, MComplex(RAX, RSI, 1, 0), R(ABI_PARAM1));
|
||||||
}
|
}
|
||||||
ADD(32, R(ESI), Imm8(size >> 3));
|
ADD(32, R(ESI), Imm8(size >> 3));
|
||||||
MOV(32, M(&GPFifo::m_gatherPipeCount), R(ESI));
|
MOV(32, M(&GPFifo::m_gatherPipeCount), R(ESI));
|
||||||
if (size != 32)
|
if (size != 32)
|
||||||
POP(EDX);
|
POP(EDX);
|
||||||
POP(ESI);
|
POP(ESI);
|
||||||
RET();
|
RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int temp32;
|
static int temp32;
|
||||||
void GenFifoFloatWrite()
|
void GenFifoFloatWrite()
|
||||||
{
|
{
|
||||||
// Assume value in XMM0
|
// Assume value in XMM0
|
||||||
PUSH(ESI);
|
PUSH(ESI);
|
||||||
PUSH(EDX);
|
PUSH(EDX);
|
||||||
MOVSS(M(&temp32), XMM0);
|
MOVSS(M(&temp32), XMM0);
|
||||||
MOV(32, R(EDX), M(&temp32));
|
MOV(32, R(EDX), M(&temp32));
|
||||||
BSWAP(32, EDX);
|
BSWAP(32, EDX);
|
||||||
MOV(32, R(EAX), Imm32((u32)(u64)GPFifo::m_gatherPipe));
|
MOV(32, R(EAX), Imm32((u32)(u64)GPFifo::m_gatherPipe));
|
||||||
MOV(32, R(ESI), M(&GPFifo::m_gatherPipeCount));
|
MOV(32, R(ESI), M(&GPFifo::m_gatherPipeCount));
|
||||||
MOV(32, MComplex(RAX, RSI, 1, 0), R(EDX));
|
MOV(32, MComplex(RAX, RSI, 1, 0), R(EDX));
|
||||||
ADD(32, R(ESI), Imm8(4));
|
ADD(32, R(ESI), Imm8(4));
|
||||||
MOV(32, M(&GPFifo::m_gatherPipeCount), R(ESI));
|
MOV(32, M(&GPFifo::m_gatherPipeCount), R(ESI));
|
||||||
POP(EDX);
|
POP(EDX);
|
||||||
POP(ESI);
|
POP(ESI);
|
||||||
RET();
|
RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenFifoXmm64Write()
|
void GenFifoXmm64Write()
|
||||||
{
|
{
|
||||||
// Assume value in XMM0. Assume pre-byteswapped (unlike the others here!)
|
// Assume value in XMM0. Assume pre-byteswapped (unlike the others here!)
|
||||||
PUSH(ESI);
|
PUSH(ESI);
|
||||||
MOV(32, R(EAX), Imm32((u32)(u64)GPFifo::m_gatherPipe));
|
MOV(32, R(EAX), Imm32((u32)(u64)GPFifo::m_gatherPipe));
|
||||||
MOV(32, R(ESI), M(&GPFifo::m_gatherPipeCount));
|
MOV(32, R(ESI), M(&GPFifo::m_gatherPipeCount));
|
||||||
MOVQ_xmm(MComplex(RAX, RSI, 1, 0), XMM0);
|
MOVQ_xmm(MComplex(RAX, RSI, 1, 0), XMM0);
|
||||||
ADD(32, R(ESI), Imm8(8));
|
ADD(32, R(ESI), Imm8(8));
|
||||||
MOV(32, M(&GPFifo::m_gatherPipeCount), R(ESI));
|
MOV(32, M(&GPFifo::m_gatherPipeCount), R(ESI));
|
||||||
POP(ESI);
|
POP(ESI);
|
||||||
RET();
|
RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateCommon()
|
void GenerateCommon()
|
||||||
{
|
{
|
||||||
computeRc = AlignCode16();
|
computeRc = AlignCode16();
|
||||||
AND(32, M(&CR), Imm32(0x0FFFFFFF));
|
AND(32, M(&CR), Imm32(0x0FFFFFFF));
|
||||||
CMP(32, R(EAX), Imm8(0));
|
CMP(32, R(EAX), Imm8(0));
|
||||||
FixupBranch pLesser = J_CC(CC_L);
|
FixupBranch pLesser = J_CC(CC_L);
|
||||||
FixupBranch pGreater = J_CC(CC_G);
|
FixupBranch pGreater = J_CC(CC_G);
|
||||||
OR(32, M(&CR), Imm32(0x20000000)); // _x86Reg == 0
|
OR(32, M(&CR), Imm32(0x20000000)); // _x86Reg == 0
|
||||||
RET();
|
RET();
|
||||||
SetJumpTarget(pGreater);
|
SetJumpTarget(pGreater);
|
||||||
OR(32, M(&CR), Imm32(0x40000000)); // _x86Reg > 0
|
OR(32, M(&CR), Imm32(0x40000000)); // _x86Reg > 0
|
||||||
RET();
|
RET();
|
||||||
SetJumpTarget(pLesser);
|
SetJumpTarget(pLesser);
|
||||||
OR(32, M(&CR), Imm32(0x80000000)); // _x86Reg < 0
|
OR(32, M(&CR), Imm32(0x80000000)); // _x86Reg < 0
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
fifoDirectWrite8 = AlignCode4();
|
fifoDirectWrite8 = AlignCode4();
|
||||||
GenFifoWrite(8);
|
GenFifoWrite(8);
|
||||||
fifoDirectWrite16 = AlignCode4();
|
fifoDirectWrite16 = AlignCode4();
|
||||||
GenFifoWrite(16);
|
GenFifoWrite(16);
|
||||||
fifoDirectWrite32 = AlignCode4();
|
fifoDirectWrite32 = AlignCode4();
|
||||||
GenFifoWrite(32);
|
GenFifoWrite(32);
|
||||||
fifoDirectWriteFloat = AlignCode4();
|
fifoDirectWriteFloat = AlignCode4();
|
||||||
GenFifoFloatWrite();
|
GenFifoFloatWrite();
|
||||||
fifoDirectWriteXmm64 = AlignCode4();
|
fifoDirectWriteXmm64 = AlignCode4();
|
||||||
GenFifoXmm64Write();
|
GenFifoXmm64Write();
|
||||||
|
|
||||||
computeRcFp = AlignCode16();
|
computeRcFp = AlignCode16();
|
||||||
//CMPSD(R(XMM0), M(&zero),
|
//CMPSD(R(XMM0), M(&zero),
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
// Fast write routines - special case the most common hardware write
|
// Fast write routines - special case the most common hardware write
|
||||||
// TODO: use this.
|
// TODO: use this.
|
||||||
// Even in x86, the param values will be in the right registers.
|
// Even in x86, the param values will be in the right registers.
|
||||||
/*
|
/*
|
||||||
const u8 *fastMemWrite8 = AlignCode16();
|
const u8 *fastMemWrite8 = AlignCode16();
|
||||||
CMP(32, R(ABI_PARAM2), Imm32(0xCC008000));
|
CMP(32, R(ABI_PARAM2), Imm32(0xCC008000));
|
||||||
FixupBranch skip_fast_write = J_CC(CC_NE, false);
|
FixupBranch skip_fast_write = J_CC(CC_NE, false);
|
||||||
MOV(32, EAX, M(&m_gatherPipeCount));
|
MOV(32, EAX, M(&m_gatherPipeCount));
|
||||||
MOV(8, MDisp(EAX, (u32)&m_gatherPipe), ABI_PARAM1);
|
MOV(8, MDisp(EAX, (u32)&m_gatherPipe), ABI_PARAM1);
|
||||||
ADD(32, 1, M(&m_gatherPipeCount));
|
ADD(32, 1, M(&m_gatherPipeCount));
|
||||||
RET();
|
RET();
|
||||||
SetJumpTarget(skip_fast_write);
|
SetJumpTarget(skip_fast_write);
|
||||||
CALL((void *)&Memory::Write_U8);*/
|
CALL((void *)&Memory::Write_U8);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Asm
|
} // namespace Asm
|
||||||
|
|
||||||
} // namespace Jit64
|
} // namespace Jit64
|
||||||
|
|
||||||
|
|
|
@ -1,197 +1,197 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "disasm.h"
|
#include "disasm.h"
|
||||||
#include "JitAsm.h"
|
#include "JitAsm.h"
|
||||||
#include "JitBackpatch.h"
|
#include "JitBackpatch.h"
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
|
|
||||||
#include "x64Emitter.h"
|
#include "x64Emitter.h"
|
||||||
#include "ABI.h"
|
#include "ABI.h"
|
||||||
#include "Thunk.h"
|
#include "Thunk.h"
|
||||||
#include "x64Analyzer.h"
|
#include "x64Analyzer.h"
|
||||||
|
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "Jit.h"
|
#include "Jit.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
namespace Jit64 {
|
namespace Jit64 {
|
||||||
|
|
||||||
extern u8 *trampolineCodePtr;
|
extern u8 *trampolineCodePtr;
|
||||||
|
|
||||||
void BackPatchError(const std::string &text, u8 *codePtr, u32 emAddress) {
|
void BackPatchError(const std::string &text, u8 *codePtr, u32 emAddress) {
|
||||||
u64 code_addr = (u64)codePtr;
|
u64 code_addr = (u64)codePtr;
|
||||||
disassembler disasm;
|
disassembler disasm;
|
||||||
char disbuf[256];
|
char disbuf[256];
|
||||||
memset(disbuf, 0, 256);
|
memset(disbuf, 0, 256);
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
disasm.disasm32
|
disasm.disasm32
|
||||||
#else
|
#else
|
||||||
disasm.disasm64
|
disasm.disasm64
|
||||||
#endif
|
#endif
|
||||||
(0, code_addr, codePtr, disbuf);
|
(0, code_addr, codePtr, disbuf);
|
||||||
PanicAlert("%s\n\n"
|
PanicAlert("%s\n\n"
|
||||||
"Error encountered accessing emulated address %08x.\n"
|
"Error encountered accessing emulated address %08x.\n"
|
||||||
"Culprit instruction: \n%s\nat %08x%08x",
|
"Culprit instruction: \n%s\nat %08x%08x",
|
||||||
text.c_str(), emAddress, disbuf, code_addr>>32, code_addr);
|
text.c_str(), emAddress, disbuf, code_addr>>32, code_addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This generates some fairly heavy trampolines, but:
|
// This generates some fairly heavy trampolines, but:
|
||||||
// 1) It's really necessary. We don't know anything about the context.
|
// 1) It's really necessary. We don't know anything about the context.
|
||||||
// 2) It doesn't really hurt. Only instructions that access I/O will get these, and there won't be
|
// 2) It doesn't really hurt. Only instructions that access I/O will get these, and there won't be
|
||||||
// that many of them in a typical program/game.
|
// that many of them in a typical program/game.
|
||||||
u8 *BackPatch(u8 *codePtr, int accessType, u32 emAddress, CONTEXT *ctx)
|
u8 *BackPatch(u8 *codePtr, int accessType, u32 emAddress, CONTEXT *ctx)
|
||||||
{
|
{
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
if (!IsInJitCode(codePtr))
|
if (!IsInJitCode(codePtr))
|
||||||
return 0; // this will become a regular crash real soon after this
|
return 0; // this will become a regular crash real soon after this
|
||||||
|
|
||||||
u8 *oldCodePtr = GetWritableCodePtr();
|
u8 *oldCodePtr = GetWritableCodePtr();
|
||||||
InstructionInfo info;
|
InstructionInfo info;
|
||||||
if (!DisassembleMov(codePtr, info, accessType)) {
|
if (!DisassembleMov(codePtr, info, accessType)) {
|
||||||
BackPatchError("BackPatch - failed to disassemble MOV instruction", codePtr, emAddress);
|
BackPatchError("BackPatch - failed to disassemble MOV instruction", codePtr, emAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (info.isMemoryWrite) {
|
if (info.isMemoryWrite) {
|
||||||
if (!Memory::IsRAMAddress(emAddress, true)) {
|
if (!Memory::IsRAMAddress(emAddress, true)) {
|
||||||
PanicAlert("Exception: Caught write to invalid address %08x", emAddress);
|
PanicAlert("Exception: Caught write to invalid address %08x", emAddress);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BackPatchError("BackPatch - determined that MOV is write, not yet supported and should have been caught before",
|
BackPatchError("BackPatch - determined that MOV is write, not yet supported and should have been caught before",
|
||||||
codePtr, emAddress);
|
codePtr, emAddress);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
if (info.operandSize != 4) {
|
if (info.operandSize != 4) {
|
||||||
BackPatchError(StringFromFormat("BackPatch - no support for operand size %i", info.operandSize), codePtr, emAddress);
|
BackPatchError(StringFromFormat("BackPatch - no support for operand size %i", info.operandSize), codePtr, emAddress);
|
||||||
}
|
}
|
||||||
u64 code_addr = (u64)codePtr;
|
u64 code_addr = (u64)codePtr;
|
||||||
X64Reg addrReg = (X64Reg)info.scaledReg;
|
X64Reg addrReg = (X64Reg)info.scaledReg;
|
||||||
X64Reg dataReg = (X64Reg)info.regOperandReg;
|
X64Reg dataReg = (X64Reg)info.regOperandReg;
|
||||||
if (info.otherReg != RBX)
|
if (info.otherReg != RBX)
|
||||||
PanicAlert("BackPatch : Base reg not RBX."
|
PanicAlert("BackPatch : Base reg not RBX."
|
||||||
"\n\nAttempted to access %08x.", emAddress);
|
"\n\nAttempted to access %08x.", emAddress);
|
||||||
//if (accessType == OP_ACCESS_WRITE)
|
//if (accessType == OP_ACCESS_WRITE)
|
||||||
// PanicAlert("BackPatch : Currently only supporting reads."
|
// PanicAlert("BackPatch : Currently only supporting reads."
|
||||||
// "\n\nAttempted to write to %08x.", emAddress);
|
// "\n\nAttempted to write to %08x.", emAddress);
|
||||||
|
|
||||||
// OK, let's write a trampoline, and a jump to it.
|
// OK, let's write a trampoline, and a jump to it.
|
||||||
// Later, let's share trampolines.
|
// Later, let's share trampolines.
|
||||||
|
|
||||||
// In the first iteration, we assume that all accesses are 32-bit. We also only deal with reads.
|
// In the first iteration, we assume that all accesses are 32-bit. We also only deal with reads.
|
||||||
// Next step - support writes, special case FIFO writes. Also, support 32-bit mode.
|
// Next step - support writes, special case FIFO writes. Also, support 32-bit mode.
|
||||||
u8 *trampoline = trampolineCodePtr;
|
u8 *trampoline = trampolineCodePtr;
|
||||||
SetCodePtr(trampolineCodePtr);
|
SetCodePtr(trampolineCodePtr);
|
||||||
|
|
||||||
if (accessType == 0)
|
if (accessType == 0)
|
||||||
{
|
{
|
||||||
// It's a read. Easy.
|
// It's a read. Easy.
|
||||||
ABI_PushAllCallerSavedRegsAndAdjustStack();
|
ABI_PushAllCallerSavedRegsAndAdjustStack();
|
||||||
MOV(32, R(ABI_PARAM1), R((X64Reg)addrReg));
|
MOV(32, R(ABI_PARAM1), R((X64Reg)addrReg));
|
||||||
if (info.displacement) {
|
if (info.displacement) {
|
||||||
ADD(32, R(ABI_PARAM1), Imm32(info.displacement));
|
ADD(32, R(ABI_PARAM1), Imm32(info.displacement));
|
||||||
}
|
}
|
||||||
switch (info.operandSize) {
|
switch (info.operandSize) {
|
||||||
case 4:
|
case 4:
|
||||||
CALL(ProtectFunction((void *)&Memory::Read_U32, 1));
|
CALL(ProtectFunction((void *)&Memory::Read_U32, 1));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BackPatchError(StringFromFormat("We don't handle the size %i yet in backpatch", info.operandSize), codePtr, emAddress);
|
BackPatchError(StringFromFormat("We don't handle the size %i yet in backpatch", info.operandSize), codePtr, emAddress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ABI_PopAllCallerSavedRegsAndAdjustStack();
|
ABI_PopAllCallerSavedRegsAndAdjustStack();
|
||||||
MOV(32, R(dataReg), R(EAX));
|
MOV(32, R(dataReg), R(EAX));
|
||||||
RET();
|
RET();
|
||||||
trampolineCodePtr = GetWritableCodePtr();
|
trampolineCodePtr = GetWritableCodePtr();
|
||||||
|
|
||||||
SetCodePtr(codePtr);
|
SetCodePtr(codePtr);
|
||||||
int bswapNopCount;
|
int bswapNopCount;
|
||||||
// Check the following BSWAP for REX byte
|
// Check the following BSWAP for REX byte
|
||||||
if ((GetCodePtr()[info.instructionSize] & 0xF0) == 0x40)
|
if ((GetCodePtr()[info.instructionSize] & 0xF0) == 0x40)
|
||||||
bswapNopCount = 3;
|
bswapNopCount = 3;
|
||||||
else
|
else
|
||||||
bswapNopCount = 2;
|
bswapNopCount = 2;
|
||||||
CALL(trampoline);
|
CALL(trampoline);
|
||||||
NOP((int)info.instructionSize + bswapNopCount - 5);
|
NOP((int)info.instructionSize + bswapNopCount - 5);
|
||||||
SetCodePtr(oldCodePtr);
|
SetCodePtr(oldCodePtr);
|
||||||
|
|
||||||
return codePtr;
|
return codePtr;
|
||||||
}
|
}
|
||||||
else if (accessType == 1)
|
else if (accessType == 1)
|
||||||
{
|
{
|
||||||
// It's a write. Yay. Remember that we don't have to be super efficient since it's "just" a
|
// It's a write. Yay. Remember that we don't have to be super efficient since it's "just" a
|
||||||
// hardware access - we can take shortcuts.
|
// hardware access - we can take shortcuts.
|
||||||
//if (emAddress == 0xCC008000)
|
//if (emAddress == 0xCC008000)
|
||||||
// PanicAlert("caught a fifo write");
|
// PanicAlert("caught a fifo write");
|
||||||
if (dataReg != EAX)
|
if (dataReg != EAX)
|
||||||
PanicAlert("Backpatch write - not through EAX");
|
PanicAlert("Backpatch write - not through EAX");
|
||||||
CMP(32, R(addrReg), Imm32(0xCC008000));
|
CMP(32, R(addrReg), Imm32(0xCC008000));
|
||||||
FixupBranch skip_fast = J_CC(CC_NE, false);
|
FixupBranch skip_fast = J_CC(CC_NE, false);
|
||||||
MOV(32, R(ABI_PARAM1), R((X64Reg)dataReg));
|
MOV(32, R(ABI_PARAM1), R((X64Reg)dataReg));
|
||||||
CALL((void*)Asm::fifoDirectWrite32);
|
CALL((void*)Asm::fifoDirectWrite32);
|
||||||
RET();
|
RET();
|
||||||
SetJumpTarget(skip_fast);
|
SetJumpTarget(skip_fast);
|
||||||
ABI_PushAllCallerSavedRegsAndAdjustStack();
|
ABI_PushAllCallerSavedRegsAndAdjustStack();
|
||||||
if (addrReg != ABI_PARAM1) {
|
if (addrReg != ABI_PARAM1) {
|
||||||
//INT3();
|
//INT3();
|
||||||
MOV(32, R(ABI_PARAM1), R((X64Reg)dataReg));
|
MOV(32, R(ABI_PARAM1), R((X64Reg)dataReg));
|
||||||
MOV(32, R(ABI_PARAM2), R((X64Reg)addrReg));
|
MOV(32, R(ABI_PARAM2), R((X64Reg)addrReg));
|
||||||
} else {
|
} else {
|
||||||
MOV(32, R(ABI_PARAM2), R((X64Reg)addrReg));
|
MOV(32, R(ABI_PARAM2), R((X64Reg)addrReg));
|
||||||
MOV(32, R(ABI_PARAM1), R((X64Reg)dataReg));
|
MOV(32, R(ABI_PARAM1), R((X64Reg)dataReg));
|
||||||
}
|
}
|
||||||
if (info.displacement) {
|
if (info.displacement) {
|
||||||
ADD(32, R(ABI_PARAM2), Imm32(info.displacement));
|
ADD(32, R(ABI_PARAM2), Imm32(info.displacement));
|
||||||
}
|
}
|
||||||
switch (info.operandSize) {
|
switch (info.operandSize) {
|
||||||
case 4:
|
case 4:
|
||||||
CALL(ProtectFunction((void *)&Memory::Write_U32, 2));
|
CALL(ProtectFunction((void *)&Memory::Write_U32, 2));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BackPatchError(StringFromFormat("We don't handle the size %i yet in backpatch", info.operandSize), codePtr, emAddress);
|
BackPatchError(StringFromFormat("We don't handle the size %i yet in backpatch", info.operandSize), codePtr, emAddress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ABI_PopAllCallerSavedRegsAndAdjustStack();
|
ABI_PopAllCallerSavedRegsAndAdjustStack();
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
trampolineCodePtr = GetWritableCodePtr();
|
trampolineCodePtr = GetWritableCodePtr();
|
||||||
|
|
||||||
// We know it's EAX so the BSWAP before will be two byte. Overwrite it.
|
// We know it's EAX so the BSWAP before will be two byte. Overwrite it.
|
||||||
SetCodePtr(codePtr - 2);
|
SetCodePtr(codePtr - 2);
|
||||||
CALL(trampoline);
|
CALL(trampoline);
|
||||||
NOP((int)info.instructionSize - 3);
|
NOP((int)info.instructionSize - 3);
|
||||||
if (info.instructionSize < 3)
|
if (info.instructionSize < 3)
|
||||||
PanicAlert("instruction too small");
|
PanicAlert("instruction too small");
|
||||||
SetCodePtr(oldCodePtr);
|
SetCodePtr(oldCodePtr);
|
||||||
|
|
||||||
// We entered here with a BSWAP-ed EAX. We'll have to swap it back.
|
// We entered here with a BSWAP-ed EAX. We'll have to swap it back.
|
||||||
ctx->Rax = _byteswap_ulong(ctx->Rax);
|
ctx->Rax = _byteswap_ulong(ctx->Rax);
|
||||||
|
|
||||||
return codePtr - 2;
|
return codePtr - 2;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,429 +1,429 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
// Enable define below to enable oprofile integration. For this to work,
|
// Enable define below to enable oprofile integration. For this to work,
|
||||||
// it requires at least oprofile version 0.9.4, and changing the build
|
// it requires at least oprofile version 0.9.4, and changing the build
|
||||||
// system to link the Dolphin executable against libopagent. Since the
|
// system to link the Dolphin executable against libopagent. Since the
|
||||||
// dependency is a little inconvenient and this is possibly a slight
|
// dependency is a little inconvenient and this is possibly a slight
|
||||||
// performance hit, it's not enabled by default, but it's useful for
|
// performance hit, it's not enabled by default, but it's useful for
|
||||||
// locating performance issues.
|
// locating performance issues.
|
||||||
//#define OPROFILE_REPORT
|
//#define OPROFILE_REPORT
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "../../Core.h"
|
#include "../../Core.h"
|
||||||
#include "MemoryUtil.h"
|
#include "MemoryUtil.h"
|
||||||
|
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
#include "../../CoreTiming.h"
|
#include "../../CoreTiming.h"
|
||||||
|
|
||||||
#include "../PowerPC.h"
|
#include "../PowerPC.h"
|
||||||
#include "../PPCTables.h"
|
#include "../PPCTables.h"
|
||||||
#include "../PPCAnalyst.h"
|
#include "../PPCAnalyst.h"
|
||||||
|
|
||||||
#include "x64Emitter.h"
|
#include "x64Emitter.h"
|
||||||
#include "x64Analyzer.h"
|
#include "x64Analyzer.h"
|
||||||
|
|
||||||
#include "Jit.h"
|
#include "Jit.h"
|
||||||
#include "JitCache.h"
|
#include "JitCache.h"
|
||||||
#include "JitAsm.h"
|
#include "JitAsm.h"
|
||||||
|
|
||||||
#include "disasm.h"
|
#include "disasm.h"
|
||||||
|
|
||||||
#ifdef OPROFILE_REPORT
|
#ifdef OPROFILE_REPORT
|
||||||
#include <opagent.h>
|
#include <opagent.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
namespace Jit64
|
namespace Jit64
|
||||||
{
|
{
|
||||||
#ifdef OPROFILE_REPORT
|
#ifdef OPROFILE_REPORT
|
||||||
op_agent_t agent;
|
op_agent_t agent;
|
||||||
#endif
|
#endif
|
||||||
static u8 *codeCache;
|
static u8 *codeCache;
|
||||||
static u8 *genFunctions;
|
static u8 *genFunctions;
|
||||||
static u8 *trampolineCache;
|
static u8 *trampolineCache;
|
||||||
u8 *trampolineCodePtr;
|
u8 *trampolineCodePtr;
|
||||||
#define INVALID_EXIT 0xFFFFFFFF
|
#define INVALID_EXIT 0xFFFFFFFF
|
||||||
void LinkBlockExits(int i);
|
void LinkBlockExits(int i);
|
||||||
void LinkBlock(int i);
|
void LinkBlock(int i);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
//CODE_SIZE = 1024*1024*8,
|
//CODE_SIZE = 1024*1024*8,
|
||||||
GEN_SIZE = 4096,
|
GEN_SIZE = 4096,
|
||||||
TRAMPOLINE_SIZE = 1024*1024,
|
TRAMPOLINE_SIZE = 1024*1024,
|
||||||
//MAX_NUM_BLOCKS = 65536,
|
//MAX_NUM_BLOCKS = 65536,
|
||||||
};
|
};
|
||||||
int CODE_SIZE = 1024*1024*16; // nonconstant to be able to have an option for it
|
int CODE_SIZE = 1024*1024*16; // nonconstant to be able to have an option for it
|
||||||
int MAX_NUM_BLOCKS = 65536*2;
|
int MAX_NUM_BLOCKS = 65536*2;
|
||||||
|
|
||||||
static u8 **blockCodePointers; // cut these in half and force below 2GB?
|
static u8 **blockCodePointers; // cut these in half and force below 2GB?
|
||||||
|
|
||||||
static std::multimap<u32, int> links_to;
|
static std::multimap<u32, int> links_to;
|
||||||
|
|
||||||
static JitBlock *blocks;
|
static JitBlock *blocks;
|
||||||
static int numBlocks;
|
static int numBlocks;
|
||||||
|
|
||||||
void DestroyBlock(int blocknum, bool invalidate);
|
void DestroyBlock(int blocknum, bool invalidate);
|
||||||
|
|
||||||
void PrintStats()
|
void PrintStats()
|
||||||
{
|
{
|
||||||
LOG(DYNA_REC, "JIT Statistics =======================");
|
LOG(DYNA_REC, "JIT Statistics =======================");
|
||||||
LOG(DYNA_REC, "Number of blocks currently: %i", numBlocks);
|
LOG(DYNA_REC, "Number of blocks currently: %i", numBlocks);
|
||||||
LOG(DYNA_REC, "Code cache size: %i b", GetCodePtr() - codeCache);
|
LOG(DYNA_REC, "Code cache size: %i b", GetCodePtr() - codeCache);
|
||||||
LOG(DYNA_REC, "======================================");
|
LOG(DYNA_REC, "======================================");
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitCache()
|
void InitCache()
|
||||||
{
|
{
|
||||||
if(Core::g_CoreStartupParameter.bJITUnlimitedCache)
|
if(Core::g_CoreStartupParameter.bJITUnlimitedCache)
|
||||||
{
|
{
|
||||||
CODE_SIZE = 1024*1024*8*8;
|
CODE_SIZE = 1024*1024*8*8;
|
||||||
MAX_NUM_BLOCKS = 65536*8;
|
MAX_NUM_BLOCKS = 65536*8;
|
||||||
}
|
}
|
||||||
|
|
||||||
codeCache = (u8*)AllocateExecutableMemory(CODE_SIZE);
|
codeCache = (u8*)AllocateExecutableMemory(CODE_SIZE);
|
||||||
genFunctions = (u8*)AllocateExecutableMemory(GEN_SIZE);
|
genFunctions = (u8*)AllocateExecutableMemory(GEN_SIZE);
|
||||||
trampolineCache = (u8*)AllocateExecutableMemory(TRAMPOLINE_SIZE);
|
trampolineCache = (u8*)AllocateExecutableMemory(TRAMPOLINE_SIZE);
|
||||||
trampolineCodePtr = trampolineCache;
|
trampolineCodePtr = trampolineCache;
|
||||||
|
|
||||||
#ifdef OPROFILE_REPORT
|
#ifdef OPROFILE_REPORT
|
||||||
agent = op_open_agent();
|
agent = op_open_agent();
|
||||||
#endif
|
#endif
|
||||||
blocks = new JitBlock[MAX_NUM_BLOCKS];
|
blocks = new JitBlock[MAX_NUM_BLOCKS];
|
||||||
blockCodePointers = new u8*[MAX_NUM_BLOCKS];
|
blockCodePointers = new u8*[MAX_NUM_BLOCKS];
|
||||||
ClearCache();
|
ClearCache();
|
||||||
SetCodePtr(genFunctions);
|
SetCodePtr(genFunctions);
|
||||||
Asm::Generate();
|
Asm::Generate();
|
||||||
// Protect the generated functions
|
// Protect the generated functions
|
||||||
WriteProtectMemory(genFunctions, GEN_SIZE, true);
|
WriteProtectMemory(genFunctions, GEN_SIZE, true);
|
||||||
SetCodePtr(codeCache);
|
SetCodePtr(codeCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShutdownCache()
|
void ShutdownCache()
|
||||||
{
|
{
|
||||||
UnWriteProtectMemory(genFunctions, GEN_SIZE, true);
|
UnWriteProtectMemory(genFunctions, GEN_SIZE, true);
|
||||||
FreeMemoryPages(codeCache, CODE_SIZE);
|
FreeMemoryPages(codeCache, CODE_SIZE);
|
||||||
FreeMemoryPages(genFunctions, GEN_SIZE);
|
FreeMemoryPages(genFunctions, GEN_SIZE);
|
||||||
FreeMemoryPages(trampolineCache, TRAMPOLINE_SIZE);
|
FreeMemoryPages(trampolineCache, TRAMPOLINE_SIZE);
|
||||||
delete [] blocks;
|
delete [] blocks;
|
||||||
delete [] blockCodePointers;
|
delete [] blockCodePointers;
|
||||||
blocks = 0;
|
blocks = 0;
|
||||||
blockCodePointers = 0;
|
blockCodePointers = 0;
|
||||||
numBlocks = 0;
|
numBlocks = 0;
|
||||||
#ifdef OPROFILE_REPORT
|
#ifdef OPROFILE_REPORT
|
||||||
op_close_agent(agent);
|
op_close_agent(agent);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
|
/* This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
|
||||||
is full and when saving and loading states */
|
is full and when saving and loading states */
|
||||||
void ClearCache()
|
void ClearCache()
|
||||||
{
|
{
|
||||||
Core::DisplayMessage("Cleared code cache.", 3000);
|
Core::DisplayMessage("Cleared code cache.", 3000);
|
||||||
// Is destroying the blocks really necessary?
|
// Is destroying the blocks really necessary?
|
||||||
for (int i = 0; i < numBlocks; i++) {
|
for (int i = 0; i < numBlocks; i++) {
|
||||||
DestroyBlock(i, false);
|
DestroyBlock(i, false);
|
||||||
}
|
}
|
||||||
links_to.clear();
|
links_to.clear();
|
||||||
trampolineCodePtr = trampolineCache;
|
trampolineCodePtr = trampolineCache;
|
||||||
numBlocks = 0;
|
numBlocks = 0;
|
||||||
memset(blockCodePointers, 0, sizeof(u8*)*MAX_NUM_BLOCKS);
|
memset(blockCodePointers, 0, sizeof(u8*)*MAX_NUM_BLOCKS);
|
||||||
memset(codeCache, 0xCC, CODE_SIZE);
|
memset(codeCache, 0xCC, CODE_SIZE);
|
||||||
SetCodePtr(codeCache);
|
SetCodePtr(codeCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyBlocksWithFlag(BlockFlag death_flag)
|
void DestroyBlocksWithFlag(BlockFlag death_flag)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < numBlocks; i++) {
|
for (int i = 0; i < numBlocks; i++) {
|
||||||
if (blocks[i].flags & death_flag) {
|
if (blocks[i].flags & death_flag) {
|
||||||
DestroyBlock(i, false);
|
DestroyBlock(i, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetCache()
|
void ResetCache()
|
||||||
{
|
{
|
||||||
ShutdownCache();
|
ShutdownCache();
|
||||||
InitCache();
|
InitCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
JitBlock *CurBlock()
|
JitBlock *CurBlock()
|
||||||
{
|
{
|
||||||
return &blocks[numBlocks];
|
return &blocks[numBlocks];
|
||||||
}
|
}
|
||||||
|
|
||||||
JitBlock *GetBlock(int no)
|
JitBlock *GetBlock(int no)
|
||||||
{
|
{
|
||||||
return &blocks[no];
|
return &blocks[no];
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetNumBlocks()
|
int GetNumBlocks()
|
||||||
{
|
{
|
||||||
return numBlocks;
|
return numBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RangeIntersect(int s1, int e1, int s2, int e2)
|
bool RangeIntersect(int s1, int e1, int s2, int e2)
|
||||||
{
|
{
|
||||||
// check if any endpoint is inside the other range
|
// check if any endpoint is inside the other range
|
||||||
if ( (s1 >= s2 && s1 <= e2) ||
|
if ( (s1 >= s2 && s1 <= e2) ||
|
||||||
(e1 >= s2 && e1 <= e2) ||
|
(e1 >= s2 && e1 <= e2) ||
|
||||||
(s2 >= s1 && s2 <= e1) ||
|
(s2 >= s1 && s2 <= e1) ||
|
||||||
(e2 >= s1 && e2 <= e1))
|
(e2 >= s1 && e2 <= e1))
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *Jit(u32 emAddress)
|
u8 *Jit(u32 emAddress)
|
||||||
{
|
{
|
||||||
if (GetCodePtr() >= codeCache + CODE_SIZE - 0x10000 || numBlocks >= MAX_NUM_BLOCKS - 1)
|
if (GetCodePtr() >= codeCache + CODE_SIZE - 0x10000 || numBlocks >= MAX_NUM_BLOCKS - 1)
|
||||||
{
|
{
|
||||||
LOG(DYNA_REC, "JIT cache full - clearing.")
|
LOG(DYNA_REC, "JIT cache full - clearing.")
|
||||||
if(Core::g_CoreStartupParameter.bJITUnlimitedCache)
|
if(Core::g_CoreStartupParameter.bJITUnlimitedCache)
|
||||||
{
|
{
|
||||||
PanicAlert("What? JIT cache still full - clearing.");
|
PanicAlert("What? JIT cache still full - clearing.");
|
||||||
}
|
}
|
||||||
ClearCache();
|
ClearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
JitBlock &b = blocks[numBlocks];
|
JitBlock &b = blocks[numBlocks];
|
||||||
b.invalid = false;
|
b.invalid = false;
|
||||||
b.originalAddress = emAddress;
|
b.originalAddress = emAddress;
|
||||||
b.originalFirstOpcode = Memory::ReadFast32(emAddress);
|
b.originalFirstOpcode = Memory::ReadFast32(emAddress);
|
||||||
b.exitAddress[0] = INVALID_EXIT;
|
b.exitAddress[0] = INVALID_EXIT;
|
||||||
b.exitAddress[1] = INVALID_EXIT;
|
b.exitAddress[1] = INVALID_EXIT;
|
||||||
b.exitPtrs[0] = 0;
|
b.exitPtrs[0] = 0;
|
||||||
b.exitPtrs[1] = 0;
|
b.exitPtrs[1] = 0;
|
||||||
b.linkStatus[0] = false;
|
b.linkStatus[0] = false;
|
||||||
b.linkStatus[1] = false;
|
b.linkStatus[1] = false;
|
||||||
|
|
||||||
blockCodePointers[numBlocks] = (u8*)DoJit(emAddress, b); //cast away const
|
blockCodePointers[numBlocks] = (u8*)DoJit(emAddress, b); //cast away const
|
||||||
Memory::WriteUnchecked_U32((JIT_OPCODE << 26) | numBlocks, emAddress);
|
Memory::WriteUnchecked_U32((JIT_OPCODE << 26) | numBlocks, emAddress);
|
||||||
|
|
||||||
if (jo.enableBlocklink) {
|
if (jo.enableBlocklink) {
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
if (b.exitAddress[i] != INVALID_EXIT) {
|
if (b.exitAddress[i] != INVALID_EXIT) {
|
||||||
links_to.insert(std::pair<u32, int>(b.exitAddress[i], numBlocks));
|
links_to.insert(std::pair<u32, int>(b.exitAddress[i], numBlocks));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *oldCodePtr = GetWritableCodePtr();
|
u8 *oldCodePtr = GetWritableCodePtr();
|
||||||
LinkBlock(numBlocks);
|
LinkBlock(numBlocks);
|
||||||
LinkBlockExits(numBlocks);
|
LinkBlockExits(numBlocks);
|
||||||
SetCodePtr(oldCodePtr);
|
SetCodePtr(oldCodePtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef OPROFILE_REPORT
|
#ifdef OPROFILE_REPORT
|
||||||
char buf[100];
|
char buf[100];
|
||||||
sprintf(buf, "EmuCode%x", emAddress);
|
sprintf(buf, "EmuCode%x", emAddress);
|
||||||
u8* blockStart = blockCodePointers[numBlocks], *blockEnd = GetWritableCodePtr();
|
u8* blockStart = blockCodePointers[numBlocks], *blockEnd = GetWritableCodePtr();
|
||||||
op_write_native_code(agent, buf, (uint64_t)blockStart,
|
op_write_native_code(agent, buf, (uint64_t)blockStart,
|
||||||
blockStart, blockEnd - blockStart);
|
blockStart, blockEnd - blockStart);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
numBlocks++; //commit the current block
|
numBlocks++; //commit the current block
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unknown_instruction(UGeckoInstruction _inst)
|
void unknown_instruction(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
// CCPU::Break();
|
// CCPU::Break();
|
||||||
PanicAlert("unknown_instruction Jit64 - Fix me ;)");
|
PanicAlert("unknown_instruction Jit64 - Fix me ;)");
|
||||||
_dbg_assert_(DYNA_REC, 0);
|
_dbg_assert_(DYNA_REC, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 **GetCodePointers()
|
u8 **GetCodePointers()
|
||||||
{
|
{
|
||||||
return blockCodePointers;
|
return blockCodePointers;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInJitCode(const u8 *codePtr) {
|
bool IsInJitCode(const u8 *codePtr) {
|
||||||
return codePtr >= codeCache && codePtr <= GetCodePtr();
|
return codePtr >= codeCache && codePtr <= GetCodePtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnterFastRun()
|
void EnterFastRun()
|
||||||
{
|
{
|
||||||
CompiledCode pExecAddr = (CompiledCode)Asm::enterCode;
|
CompiledCode pExecAddr = (CompiledCode)Asm::enterCode;
|
||||||
pExecAddr();
|
pExecAddr();
|
||||||
//Will return when PowerPC::state changes
|
//Will return when PowerPC::state changes
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetBlockNumberFromAddress(u32 addr)
|
int GetBlockNumberFromAddress(u32 addr)
|
||||||
{
|
{
|
||||||
if (!blocks)
|
if (!blocks)
|
||||||
return -1;
|
return -1;
|
||||||
u32 code = Memory::ReadFast32(addr);
|
u32 code = Memory::ReadFast32(addr);
|
||||||
if ((code >> 26) == JIT_OPCODE)
|
if ((code >> 26) == JIT_OPCODE)
|
||||||
{
|
{
|
||||||
//jitted code
|
//jitted code
|
||||||
unsigned int blockNum = code & 0x03FFFFFF;
|
unsigned int blockNum = code & 0x03FFFFFF;
|
||||||
if (blockNum >= (unsigned int)numBlocks) {
|
if (blockNum >= (unsigned int)numBlocks) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blocks[blockNum].originalAddress != addr)
|
if (blocks[blockNum].originalAddress != addr)
|
||||||
{
|
{
|
||||||
//_assert_msg_(DYNA_REC, 0, "GetBlockFromAddress %08x - No match - This is BAD", addr);
|
//_assert_msg_(DYNA_REC, 0, "GetBlockFromAddress %08x - No match - This is BAD", addr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return blockNum;
|
return blockNum;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetOriginalCode(u32 address)
|
u32 GetOriginalCode(u32 address)
|
||||||
{
|
{
|
||||||
int num = GetBlockNumberFromAddress(address);
|
int num = GetBlockNumberFromAddress(address);
|
||||||
if (num == -1)
|
if (num == -1)
|
||||||
return Memory::ReadUnchecked_U32(address);
|
return Memory::ReadUnchecked_U32(address);
|
||||||
else
|
else
|
||||||
return blocks[num].originalFirstOpcode;
|
return blocks[num].originalFirstOpcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompiledCode GetCompiledCode(u32 address)
|
CompiledCode GetCompiledCode(u32 address)
|
||||||
{
|
{
|
||||||
int num = GetBlockNumberFromAddress(address);
|
int num = GetBlockNumberFromAddress(address);
|
||||||
if (num == -1)
|
if (num == -1)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return (CompiledCode)blockCodePointers[num];
|
return (CompiledCode)blockCodePointers[num];
|
||||||
}
|
}
|
||||||
|
|
||||||
CompiledCode GetCompiledCodeFromBlock(int blockNumber)
|
CompiledCode GetCompiledCodeFromBlock(int blockNumber)
|
||||||
{
|
{
|
||||||
return (CompiledCode)blockCodePointers[blockNumber];
|
return (CompiledCode)blockCodePointers[blockNumber];
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetCodeSize() {
|
int GetCodeSize() {
|
||||||
return (int)(GetCodePtr() - codeCache);
|
return (int)(GetCodePtr() - codeCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Block linker
|
//Block linker
|
||||||
//Make sure to have as many blocks as possible compiled before calling this
|
//Make sure to have as many blocks as possible compiled before calling this
|
||||||
//It's O(N), so it's fast :)
|
//It's O(N), so it's fast :)
|
||||||
//Can be faster by doing a queue for blocks to link up, and only process those
|
//Can be faster by doing a queue for blocks to link up, and only process those
|
||||||
//Should probably be done
|
//Should probably be done
|
||||||
|
|
||||||
void LinkBlockExits(int i)
|
void LinkBlockExits(int i)
|
||||||
{
|
{
|
||||||
JitBlock &b = blocks[i];
|
JitBlock &b = blocks[i];
|
||||||
if (b.invalid)
|
if (b.invalid)
|
||||||
{
|
{
|
||||||
// This block is dead. Don't relink it.
|
// This block is dead. Don't relink it.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int e = 0; e < 2; e++)
|
for (int e = 0; e < 2; e++)
|
||||||
{
|
{
|
||||||
if (b.exitAddress[e] != INVALID_EXIT && !b.linkStatus[e])
|
if (b.exitAddress[e] != INVALID_EXIT && !b.linkStatus[e])
|
||||||
{
|
{
|
||||||
int destinationBlock = GetBlockNumberFromAddress(b.exitAddress[e]);
|
int destinationBlock = GetBlockNumberFromAddress(b.exitAddress[e]);
|
||||||
if (destinationBlock != -1)
|
if (destinationBlock != -1)
|
||||||
{
|
{
|
||||||
SetCodePtr(b.exitPtrs[e]);
|
SetCodePtr(b.exitPtrs[e]);
|
||||||
JMP(blocks[destinationBlock].checkedEntry, true);
|
JMP(blocks[destinationBlock].checkedEntry, true);
|
||||||
b.linkStatus[e] = true;
|
b.linkStatus[e] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if ((b.exitAddress[0] == INVALID_EXIT || b.linkStatus[0]) &&
|
if ((b.exitAddress[0] == INVALID_EXIT || b.linkStatus[0]) &&
|
||||||
(b.exitAddress[1] == INVALID_EXIT || b.linkStatus[1])) {
|
(b.exitAddress[1] == INVALID_EXIT || b.linkStatus[1])) {
|
||||||
unlinked.erase(iter);
|
unlinked.erase(iter);
|
||||||
if (unlinked.size() > 4000) PanicAlert("Removed from unlinked. Size = %i", unlinked.size());
|
if (unlinked.size() > 4000) PanicAlert("Removed from unlinked. Size = %i", unlinked.size());
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
using namespace std;
|
using namespace std;
|
||||||
void LinkBlock(int i)
|
void LinkBlock(int i)
|
||||||
{
|
{
|
||||||
LinkBlockExits(i);
|
LinkBlockExits(i);
|
||||||
JitBlock &b = blocks[i];
|
JitBlock &b = blocks[i];
|
||||||
std::map<u32, int>::iterator iter;
|
std::map<u32, int>::iterator iter;
|
||||||
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
|
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
|
||||||
// equal_range(b) returns pair<iterator,iterator> representing the range
|
// equal_range(b) returns pair<iterator,iterator> representing the range
|
||||||
// of element with key b
|
// of element with key b
|
||||||
ppp = links_to.equal_range(b.originalAddress);
|
ppp = links_to.equal_range(b.originalAddress);
|
||||||
if (ppp.first == ppp.second)
|
if (ppp.first == ppp.second)
|
||||||
return;
|
return;
|
||||||
for (multimap<u32, int>::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) {
|
for (multimap<u32, int>::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) {
|
||||||
// PanicAlert("Linking block %i to block %i", iter2->second, i);
|
// PanicAlert("Linking block %i to block %i", iter2->second, i);
|
||||||
LinkBlockExits(iter2->second);
|
LinkBlockExits(iter2->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyBlock(int blocknum, bool invalidate)
|
void DestroyBlock(int blocknum, bool invalidate)
|
||||||
{
|
{
|
||||||
u32 codebytes = (JIT_OPCODE << 26) | blocknum; //generate from i
|
u32 codebytes = (JIT_OPCODE << 26) | blocknum; //generate from i
|
||||||
JitBlock &b = blocks[blocknum];
|
JitBlock &b = blocks[blocknum];
|
||||||
b.invalid = 1;
|
b.invalid = 1;
|
||||||
if (codebytes == Memory::ReadFast32(b.originalAddress))
|
if (codebytes == Memory::ReadFast32(b.originalAddress))
|
||||||
{
|
{
|
||||||
//nobody has changed it, good
|
//nobody has changed it, good
|
||||||
Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress);
|
Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress);
|
||||||
}
|
}
|
||||||
else if (!invalidate)
|
else if (!invalidate)
|
||||||
{
|
{
|
||||||
//PanicAlert("Detected code overwrite");
|
//PanicAlert("Detected code overwrite");
|
||||||
//else, we may be in trouble, since we apparently know of this block but it's been
|
//else, we may be in trouble, since we apparently know of this block but it's been
|
||||||
//overwritten. We should have thrown it out before, on instruction cache invalidate or something.
|
//overwritten. We should have thrown it out before, on instruction cache invalidate or something.
|
||||||
//Not ne cessarily bad though , if a game has simply thrown away a lot of code and is now using the space
|
//Not ne cessarily bad though , if a game has simply thrown away a lot of code and is now using the space
|
||||||
//for something else, then it's fine.
|
//for something else, then it's fine.
|
||||||
LOG(MASTER_LOG, "WARNING - ClearCache detected code overwrite @ %08x", blocks[blocknum].originalAddress);
|
LOG(MASTER_LOG, "WARNING - ClearCache detected code overwrite @ %08x", blocks[blocknum].originalAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't unlink blocks, we just send anyone who tries to run them back to the dispatcher.
|
// We don't unlink blocks, we just send anyone who tries to run them back to the dispatcher.
|
||||||
// Not entirely ideal, but .. pretty good.
|
// Not entirely ideal, but .. pretty good.
|
||||||
|
|
||||||
// TODO - make sure that the below stuff really is safe.
|
// TODO - make sure that the below stuff really is safe.
|
||||||
u8 *prev_code = GetWritableCodePtr();
|
u8 *prev_code = GetWritableCodePtr();
|
||||||
// Spurious entrances from previously linked blocks can only come through checkedEntry
|
// Spurious entrances from previously linked blocks can only come through checkedEntry
|
||||||
SetCodePtr((u8*)b.checkedEntry);
|
SetCodePtr((u8*)b.checkedEntry);
|
||||||
MOV(32, M(&PC), Imm32(b.originalAddress));
|
MOV(32, M(&PC), Imm32(b.originalAddress));
|
||||||
JMP(Asm::dispatcher, true);
|
JMP(Asm::dispatcher, true);
|
||||||
SetCodePtr(blockCodePointers[blocknum]);
|
SetCodePtr(blockCodePointers[blocknum]);
|
||||||
MOV(32, M(&PC), Imm32(b.originalAddress));
|
MOV(32, M(&PC), Imm32(b.originalAddress));
|
||||||
JMP(Asm::dispatcher, true);
|
JMP(Asm::dispatcher, true);
|
||||||
SetCodePtr(prev_code); // reset code pointer
|
SetCodePtr(prev_code); // reset code pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BLR_OP 0x4e800020
|
#define BLR_OP 0x4e800020
|
||||||
|
|
||||||
void InvalidateCodeRange(u32 address, u32 length)
|
void InvalidateCodeRange(u32 address, u32 length)
|
||||||
{
|
{
|
||||||
if (!jo.enableBlocklink)
|
if (!jo.enableBlocklink)
|
||||||
return;
|
return;
|
||||||
return;
|
return;
|
||||||
//This is slow but should be safe (zelda needs it for block linking)
|
//This is slow but should be safe (zelda needs it for block linking)
|
||||||
for (int i = 0; i < numBlocks; i++)
|
for (int i = 0; i < numBlocks; i++)
|
||||||
{
|
{
|
||||||
if (RangeIntersect(blocks[i].originalAddress, blocks[i].originalAddress+blocks[i].originalSize,
|
if (RangeIntersect(blocks[i].originalAddress, blocks[i].originalAddress+blocks[i].originalSize,
|
||||||
address, address + length))
|
address, address + length))
|
||||||
{
|
{
|
||||||
DestroyBlock(i, true);
|
DestroyBlock(i, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,59 +1,59 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
#include "JitCore.h"
|
#include "JitCore.h"
|
||||||
#include "JitCache.h"
|
#include "JitCache.h"
|
||||||
#include "JitAsm.h"
|
#include "JitAsm.h"
|
||||||
#include "Jit.h"
|
#include "Jit.h"
|
||||||
|
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
#include "../../HW/CPU.h"
|
#include "../../HW/CPU.h"
|
||||||
#include "../../HW/DSP.h"
|
#include "../../HW/DSP.h"
|
||||||
#include "../../HW/GPFifo.h"
|
#include "../../HW/GPFifo.h"
|
||||||
|
|
||||||
#include "../../HW/VideoInterface.h"
|
#include "../../HW/VideoInterface.h"
|
||||||
#include "../../HW/SerialInterface.h"
|
#include "../../HW/SerialInterface.h"
|
||||||
#include "../../Core.h"
|
#include "../../Core.h"
|
||||||
|
|
||||||
namespace Jit64
|
namespace Jit64
|
||||||
{
|
{
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
::Jit64::Init();
|
::Jit64::Init();
|
||||||
InitCache();
|
InitCache();
|
||||||
Asm::compareEnabled = ::Core::g_CoreStartupParameter.bRunCompareClient;
|
Asm::compareEnabled = ::Core::g_CoreStartupParameter.bRunCompareClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
ShutdownCache();
|
ShutdownCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleStep()
|
void SingleStep()
|
||||||
{
|
{
|
||||||
Run();
|
Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Run()
|
void Run()
|
||||||
{
|
{
|
||||||
EnterFastRun();
|
EnterFastRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,397 +1,397 @@
|
||||||
// Copyright (C) 2003-2008 Dolphin Project.
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, version 2.0.
|
// the Free Software Foundation, version 2.0.
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License 2.0 for more details.
|
// GNU General Public License 2.0 for more details.
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
// If not, see http://www.gnu.org/licenses/
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
#include "../PowerPC.h"
|
#include "../PowerPC.h"
|
||||||
#include "../PPCTables.h"
|
#include "../PPCTables.h"
|
||||||
#include "../PPCAnalyst.h"
|
#include "../PPCAnalyst.h"
|
||||||
#include "Jit.h"
|
#include "Jit.h"
|
||||||
#include "JitCache.h"
|
#include "JitCache.h"
|
||||||
#include "JitAsm.h"
|
#include "JitAsm.h"
|
||||||
#include "JitRegCache.h"
|
#include "JitRegCache.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
using namespace PowerPC;
|
using namespace PowerPC;
|
||||||
|
|
||||||
namespace Jit64
|
namespace Jit64
|
||||||
{
|
{
|
||||||
GPRRegCache gpr;
|
GPRRegCache gpr;
|
||||||
FPURegCache fpr;
|
FPURegCache fpr;
|
||||||
|
|
||||||
void RegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
void RegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUMXREGS; i++)
|
for (int i = 0; i < NUMXREGS; i++)
|
||||||
{
|
{
|
||||||
xregs[i].free = true;
|
xregs[i].free = true;
|
||||||
xregs[i].dirty = false;
|
xregs[i].dirty = false;
|
||||||
xlocks[i] = false;
|
xlocks[i] = false;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 32; i++)
|
for (int i = 0; i < 32; i++)
|
||||||
{
|
{
|
||||||
regs[i].location = GetDefaultLocation(i);
|
regs[i].location = GetDefaultLocation(i);
|
||||||
regs[i].away = false;
|
regs[i].away = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: sort to find the most popular regs
|
// todo: sort to find the most popular regs
|
||||||
/*
|
/*
|
||||||
int maxPreload = 2;
|
int maxPreload = 2;
|
||||||
for (int i = 0; i < 32; i++)
|
for (int i = 0; i < 32; i++)
|
||||||
{
|
{
|
||||||
if (stats.numReads[i] > 2 || stats.numWrites[i] >= 2)
|
if (stats.numReads[i] > 2 || stats.numWrites[i] >= 2)
|
||||||
{
|
{
|
||||||
LoadToX64(i, true, false); //stats.firstRead[i] <= stats.firstWrite[i], false);
|
LoadToX64(i, true, false); //stats.firstRead[i] <= stats.firstWrite[i], false);
|
||||||
maxPreload--;
|
maxPreload--;
|
||||||
if (!maxPreload)
|
if (!maxPreload)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
//Find top regs - preload them (load bursts ain't bad)
|
//Find top regs - preload them (load bursts ain't bad)
|
||||||
//But only preload IF written OR reads >= 3
|
//But only preload IF written OR reads >= 3
|
||||||
}
|
}
|
||||||
|
|
||||||
// these are powerpc reg indices
|
// these are powerpc reg indices
|
||||||
void RegCache::Lock(int p1, int p2, int p3, int p4)
|
void RegCache::Lock(int p1, int p2, int p3, int p4)
|
||||||
{
|
{
|
||||||
locks[p1] = true;
|
locks[p1] = true;
|
||||||
if (p2 != 0xFF) locks[p2] = true;
|
if (p2 != 0xFF) locks[p2] = true;
|
||||||
if (p3 != 0xFF) locks[p3] = true;
|
if (p3 != 0xFF) locks[p3] = true;
|
||||||
if (p4 != 0xFF) locks[p4] = true;
|
if (p4 != 0xFF) locks[p4] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// these are x64 reg indices
|
// these are x64 reg indices
|
||||||
void RegCache::LockX(int x1, int x2, int x3, int x4)
|
void RegCache::LockX(int x1, int x2, int x3, int x4)
|
||||||
{
|
{
|
||||||
if (xlocks[x1]) {
|
if (xlocks[x1]) {
|
||||||
PanicAlert("RegCache: x %i already locked!");
|
PanicAlert("RegCache: x %i already locked!");
|
||||||
}
|
}
|
||||||
xlocks[x1] = true;
|
xlocks[x1] = true;
|
||||||
if (x2 != 0xFF) xlocks[x2] = true;
|
if (x2 != 0xFF) xlocks[x2] = true;
|
||||||
if (x3 != 0xFF) xlocks[x3] = true;
|
if (x3 != 0xFF) xlocks[x3] = true;
|
||||||
if (x4 != 0xFF) xlocks[x4] = true;
|
if (x4 != 0xFF) xlocks[x4] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegCache::IsFreeX(int xreg) const
|
bool RegCache::IsFreeX(int xreg) const
|
||||||
{
|
{
|
||||||
return xregs[xreg].free && !xlocks[xreg];
|
return xregs[xreg].free && !xlocks[xreg];
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::UnlockAll()
|
void RegCache::UnlockAll()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 32; i++)
|
for (int i = 0; i < 32; i++)
|
||||||
locks[i] = false;
|
locks[i] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::UnlockAllX()
|
void RegCache::UnlockAllX()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUMXREGS; i++)
|
for (int i = 0; i < NUMXREGS; i++)
|
||||||
xlocks[i] = false;
|
xlocks[i] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
X64Reg RegCache::GetFreeXReg()
|
X64Reg RegCache::GetFreeXReg()
|
||||||
{
|
{
|
||||||
int aCount;
|
int aCount;
|
||||||
const int *aOrder = GetAllocationOrder(aCount);
|
const int *aOrder = GetAllocationOrder(aCount);
|
||||||
for (int i = 0; i < aCount; i++)
|
for (int i = 0; i < aCount; i++)
|
||||||
{
|
{
|
||||||
X64Reg xr = (X64Reg)aOrder[i];
|
X64Reg xr = (X64Reg)aOrder[i];
|
||||||
if (!xlocks[xr] && xregs[xr].free)
|
if (!xlocks[xr] && xregs[xr].free)
|
||||||
{
|
{
|
||||||
return (X64Reg)xr;
|
return (X64Reg)xr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Okay, not found :( Force grab one
|
//Okay, not found :( Force grab one
|
||||||
|
|
||||||
//TODO - add a pass to grab xregs whose ppcreg is not used in the next 3 instructions
|
//TODO - add a pass to grab xregs whose ppcreg is not used in the next 3 instructions
|
||||||
for (int i = 0; i < aCount; i++)
|
for (int i = 0; i < aCount; i++)
|
||||||
{
|
{
|
||||||
X64Reg xr = (X64Reg)aOrder[i];
|
X64Reg xr = (X64Reg)aOrder[i];
|
||||||
if (xlocks[xr])
|
if (xlocks[xr])
|
||||||
continue;
|
continue;
|
||||||
int preg = xregs[xr].ppcReg;
|
int preg = xregs[xr].ppcReg;
|
||||||
if (!locks[preg])
|
if (!locks[preg])
|
||||||
{
|
{
|
||||||
StoreFromX64(preg);
|
StoreFromX64(preg);
|
||||||
return xr;
|
return xr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Still no dice? Die!
|
//Still no dice? Die!
|
||||||
_assert_msg_(DYNA_REC, 0, "Regcache ran out of regs");
|
_assert_msg_(DYNA_REC, 0, "Regcache ran out of regs");
|
||||||
return (X64Reg) -1;
|
return (X64Reg) -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::SaveState()
|
void RegCache::SaveState()
|
||||||
{
|
{
|
||||||
memcpy(saved_locks, locks, sizeof(locks));
|
memcpy(saved_locks, locks, sizeof(locks));
|
||||||
memcpy(saved_xlocks, xlocks, sizeof(xlocks));
|
memcpy(saved_xlocks, xlocks, sizeof(xlocks));
|
||||||
memcpy(saved_regs, regs, sizeof(regs));
|
memcpy(saved_regs, regs, sizeof(regs));
|
||||||
memcpy(saved_xregs, xregs, sizeof(xregs));
|
memcpy(saved_xregs, xregs, sizeof(xregs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::LoadState()
|
void RegCache::LoadState()
|
||||||
{
|
{
|
||||||
memcpy(xlocks, saved_xlocks, sizeof(xlocks));
|
memcpy(xlocks, saved_xlocks, sizeof(xlocks));
|
||||||
memcpy(locks, saved_locks, sizeof(locks));
|
memcpy(locks, saved_locks, sizeof(locks));
|
||||||
memcpy(regs, saved_regs, sizeof(regs));
|
memcpy(regs, saved_regs, sizeof(regs));
|
||||||
memcpy(xregs, saved_xregs, sizeof(xregs));
|
memcpy(xregs, saved_xregs, sizeof(xregs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::FlushR(X64Reg reg)
|
void RegCache::FlushR(X64Reg reg)
|
||||||
{
|
{
|
||||||
if (reg >= NUMXREGS)
|
if (reg >= NUMXREGS)
|
||||||
PanicAlert("Flushing non existent reg");
|
PanicAlert("Flushing non existent reg");
|
||||||
if (!xregs[reg].free)
|
if (!xregs[reg].free)
|
||||||
{
|
{
|
||||||
StoreFromX64(xregs[reg].ppcReg);
|
StoreFromX64(xregs[reg].ppcReg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::SanityCheck() const
|
void RegCache::SanityCheck() const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 32; i++) {
|
for (int i = 0; i < 32; i++) {
|
||||||
if (regs[i].away) {
|
if (regs[i].away) {
|
||||||
if (regs[i].location.IsSimpleReg()) {
|
if (regs[i].location.IsSimpleReg()) {
|
||||||
Gen::X64Reg simple = regs[i].location.GetSimpleReg();
|
Gen::X64Reg simple = regs[i].location.GetSimpleReg();
|
||||||
if (xlocks[simple]) {
|
if (xlocks[simple]) {
|
||||||
PanicAlert("%08x : PPC Reg %i is in locked x64 register %i", js.compilerPC, i, regs[i].location.GetSimpleReg());
|
PanicAlert("%08x : PPC Reg %i is in locked x64 register %i", js.compilerPC, i, regs[i].location.GetSimpleReg());
|
||||||
}
|
}
|
||||||
if (xregs[simple].ppcReg != i) {
|
if (xregs[simple].ppcReg != i) {
|
||||||
PanicAlert("%08x : Xreg/ppcreg mismatch");
|
PanicAlert("%08x : Xreg/ppcreg mismatch");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::DiscardRegContentsIfCached(int preg)
|
void RegCache::DiscardRegContentsIfCached(int preg)
|
||||||
{
|
{
|
||||||
if (regs[preg].away && regs[preg].location.IsSimpleReg())
|
if (regs[preg].away && regs[preg].location.IsSimpleReg())
|
||||||
{
|
{
|
||||||
xregs[regs[preg].location.GetSimpleReg()].free = true;
|
xregs[regs[preg].location.GetSimpleReg()].free = true;
|
||||||
xregs[regs[preg].location.GetSimpleReg()].dirty = false;
|
xregs[regs[preg].location.GetSimpleReg()].dirty = false;
|
||||||
regs[preg].away = false;
|
regs[preg].away = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GPRRegCache::SetImmediate32(int preg, u32 immValue)
|
void GPRRegCache::SetImmediate32(int preg, u32 immValue)
|
||||||
{
|
{
|
||||||
DiscardRegContentsIfCached(preg);
|
DiscardRegContentsIfCached(preg);
|
||||||
regs[preg].away = true;
|
regs[preg].away = true;
|
||||||
regs[preg].location = Imm32(immValue);
|
regs[preg].location = Imm32(immValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPRRegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
void GPRRegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
||||||
{
|
{
|
||||||
RegCache::Start(stats);
|
RegCache::Start(stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FPURegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
void FPURegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
||||||
{
|
{
|
||||||
RegCache::Start(stats);
|
RegCache::Start(stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int *GPRRegCache::GetAllocationOrder(int &count)
|
const int *GPRRegCache::GetAllocationOrder(int &count)
|
||||||
{
|
{
|
||||||
static const int allocationOrder[] =
|
static const int allocationOrder[] =
|
||||||
{
|
{
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
RSI, RDI, R12, R13, R14, R8, R9, R10, R11 //, RCX
|
RSI, RDI, R12, R13, R14, R8, R9, R10, R11 //, RCX
|
||||||
#else
|
#else
|
||||||
RBP, R12, R13, R14, R8, R9, R10, R11, //, RCX
|
RBP, R12, R13, R14, R8, R9, R10, R11, //, RCX
|
||||||
#endif
|
#endif
|
||||||
#elif _M_IX86
|
#elif _M_IX86
|
||||||
ESI, EDI, EBX, EBP, EDX, ECX,
|
ESI, EDI, EBX, EBP, EDX, ECX,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
count = sizeof(allocationOrder) / sizeof(const int);
|
count = sizeof(allocationOrder) / sizeof(const int);
|
||||||
return allocationOrder;
|
return allocationOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int *FPURegCache::GetAllocationOrder(int &count)
|
const int *FPURegCache::GetAllocationOrder(int &count)
|
||||||
{
|
{
|
||||||
static const int allocationOrder[] =
|
static const int allocationOrder[] =
|
||||||
{
|
{
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5
|
XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5
|
||||||
#elif _M_IX86
|
#elif _M_IX86
|
||||||
XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
|
XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
count = sizeof(allocationOrder) / sizeof(int);
|
count = sizeof(allocationOrder) / sizeof(int);
|
||||||
return allocationOrder;
|
return allocationOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpArg GPRRegCache::GetDefaultLocation(int reg) const
|
OpArg GPRRegCache::GetDefaultLocation(int reg) const
|
||||||
{
|
{
|
||||||
return M(&ppcState.gpr[reg]);
|
return M(&ppcState.gpr[reg]);
|
||||||
}
|
}
|
||||||
|
|
||||||
OpArg FPURegCache::GetDefaultLocation(int reg) const
|
OpArg FPURegCache::GetDefaultLocation(int reg) const
|
||||||
{
|
{
|
||||||
return M(&ppcState.ps[reg][0]);
|
return M(&ppcState.ps[reg][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::KillImmediate(int preg)
|
void RegCache::KillImmediate(int preg)
|
||||||
{
|
{
|
||||||
if (regs[preg].away && regs[preg].location.IsImm())
|
if (regs[preg].away && regs[preg].location.IsImm())
|
||||||
{
|
{
|
||||||
LoadToX64(preg, true, true);
|
LoadToX64(preg, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPRRegCache::LoadToX64(int i, bool doLoad, bool makeDirty)
|
void GPRRegCache::LoadToX64(int i, bool doLoad, bool makeDirty)
|
||||||
{
|
{
|
||||||
if (!regs[i].away && regs[i].location.IsImm())
|
if (!regs[i].away && regs[i].location.IsImm())
|
||||||
PanicAlert("Bad immedaite");
|
PanicAlert("Bad immedaite");
|
||||||
|
|
||||||
if (!regs[i].away || (regs[i].away && regs[i].location.IsImm()))
|
if (!regs[i].away || (regs[i].away && regs[i].location.IsImm()))
|
||||||
{
|
{
|
||||||
X64Reg xr = GetFreeXReg();
|
X64Reg xr = GetFreeXReg();
|
||||||
if (xregs[xr].dirty) PanicAlert("Xreg already dirty");
|
if (xregs[xr].dirty) PanicAlert("Xreg already dirty");
|
||||||
if (xlocks[xr]) PanicAlert("GetFreeXReg returned locked register");
|
if (xlocks[xr]) PanicAlert("GetFreeXReg returned locked register");
|
||||||
xregs[xr].free = false;
|
xregs[xr].free = false;
|
||||||
xregs[xr].ppcReg = i;
|
xregs[xr].ppcReg = i;
|
||||||
xregs[xr].dirty = makeDirty || regs[i].location.IsImm();
|
xregs[xr].dirty = makeDirty || regs[i].location.IsImm();
|
||||||
OpArg newloc = ::Gen::R(xr);
|
OpArg newloc = ::Gen::R(xr);
|
||||||
if (doLoad || regs[i].location.IsImm())
|
if (doLoad || regs[i].location.IsImm())
|
||||||
MOV(32, newloc, regs[i].location);
|
MOV(32, newloc, regs[i].location);
|
||||||
for (int j = 0; j < 32; j++)
|
for (int j = 0; j < 32; j++)
|
||||||
{
|
{
|
||||||
if (i != j && regs[j].location.IsSimpleReg() && regs[j].location.GetSimpleReg() == xr)
|
if (i != j && regs[j].location.IsSimpleReg() && regs[j].location.GetSimpleReg() == xr)
|
||||||
{
|
{
|
||||||
Crash();
|
Crash();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
regs[i].away = true;
|
regs[i].away = true;
|
||||||
regs[i].location = newloc;
|
regs[i].location = newloc;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// reg location must be simplereg; memory locations
|
// reg location must be simplereg; memory locations
|
||||||
// and immediates are taken care of above.
|
// and immediates are taken care of above.
|
||||||
xregs[RX(i)].dirty |= makeDirty;
|
xregs[RX(i)].dirty |= makeDirty;
|
||||||
}
|
}
|
||||||
if (xlocks[RX(i)]) {
|
if (xlocks[RX(i)]) {
|
||||||
PanicAlert("Seriously WTF, this reg should have been flushed");
|
PanicAlert("Seriously WTF, this reg should have been flushed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPRRegCache::StoreFromX64(int i)
|
void GPRRegCache::StoreFromX64(int i)
|
||||||
{
|
{
|
||||||
if (regs[i].away)
|
if (regs[i].away)
|
||||||
{
|
{
|
||||||
bool doStore;
|
bool doStore;
|
||||||
if (regs[i].location.IsSimpleReg())
|
if (regs[i].location.IsSimpleReg())
|
||||||
{
|
{
|
||||||
X64Reg xr = RX(i);
|
X64Reg xr = RX(i);
|
||||||
xregs[xr].free = true;
|
xregs[xr].free = true;
|
||||||
xregs[xr].ppcReg = -1;
|
xregs[xr].ppcReg = -1;
|
||||||
doStore = xregs[xr].dirty;
|
doStore = xregs[xr].dirty;
|
||||||
xregs[xr].dirty = false;
|
xregs[xr].dirty = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//must be immediate - do nothing
|
//must be immediate - do nothing
|
||||||
doStore = true;
|
doStore = true;
|
||||||
}
|
}
|
||||||
OpArg newLoc = GetDefaultLocation(i);
|
OpArg newLoc = GetDefaultLocation(i);
|
||||||
// if (doStore) //<-- Breaks JIT compilation
|
// if (doStore) //<-- Breaks JIT compilation
|
||||||
MOV(32, newLoc, regs[i].location);
|
MOV(32, newLoc, regs[i].location);
|
||||||
regs[i].location = newLoc;
|
regs[i].location = newLoc;
|
||||||
regs[i].away = false;
|
regs[i].away = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FPURegCache::LoadToX64(int i, bool doLoad, bool makeDirty)
|
void FPURegCache::LoadToX64(int i, bool doLoad, bool makeDirty)
|
||||||
{
|
{
|
||||||
_assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - load - imm");
|
_assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - load - imm");
|
||||||
if (!regs[i].away)
|
if (!regs[i].away)
|
||||||
{
|
{
|
||||||
// Reg is at home in the memory register file. Let's pull it out.
|
// Reg is at home in the memory register file. Let's pull it out.
|
||||||
X64Reg xr = GetFreeXReg();
|
X64Reg xr = GetFreeXReg();
|
||||||
_assert_msg_(DYNA_REC, xr >= 0 && xr < NUMXREGS, "WTF - load - invalid reg");
|
_assert_msg_(DYNA_REC, xr >= 0 && xr < NUMXREGS, "WTF - load - invalid reg");
|
||||||
xregs[xr].ppcReg = i;
|
xregs[xr].ppcReg = i;
|
||||||
xregs[xr].free = false;
|
xregs[xr].free = false;
|
||||||
xregs[xr].dirty = makeDirty;
|
xregs[xr].dirty = makeDirty;
|
||||||
OpArg newloc = ::Gen::R(xr);
|
OpArg newloc = ::Gen::R(xr);
|
||||||
if (doLoad) {
|
if (doLoad) {
|
||||||
if (!regs[i].location.IsImm() && (regs[i].location.offset & 0xF)) {
|
if (!regs[i].location.IsImm() && (regs[i].location.offset & 0xF)) {
|
||||||
PanicAlert("WARNING - misaligned fp register location %i", i);
|
PanicAlert("WARNING - misaligned fp register location %i", i);
|
||||||
}
|
}
|
||||||
MOVAPD(xr, regs[i].location);
|
MOVAPD(xr, regs[i].location);
|
||||||
}
|
}
|
||||||
regs[i].location = newloc;
|
regs[i].location = newloc;
|
||||||
regs[i].away = true;
|
regs[i].away = true;
|
||||||
} else {
|
} else {
|
||||||
// There are no immediates in the FPR reg file, so we already had this in a register. Make dirty as necessary.
|
// There are no immediates in the FPR reg file, so we already had this in a register. Make dirty as necessary.
|
||||||
xregs[RX(i)].dirty |= makeDirty;
|
xregs[RX(i)].dirty |= makeDirty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FPURegCache::StoreFromX64(int i)
|
void FPURegCache::StoreFromX64(int i)
|
||||||
{
|
{
|
||||||
_assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - store - imm");
|
_assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - store - imm");
|
||||||
if (regs[i].away)
|
if (regs[i].away)
|
||||||
{
|
{
|
||||||
X64Reg xr = regs[i].location.GetSimpleReg();
|
X64Reg xr = regs[i].location.GetSimpleReg();
|
||||||
_assert_msg_(DYNA_REC, xr >= 0 && xr < NUMXREGS, "WTF - store - invalid reg");
|
_assert_msg_(DYNA_REC, xr >= 0 && xr < NUMXREGS, "WTF - store - invalid reg");
|
||||||
xregs[xr].free = true;
|
xregs[xr].free = true;
|
||||||
xregs[xr].dirty = false;
|
xregs[xr].dirty = false;
|
||||||
xregs[xr].ppcReg = -1;
|
xregs[xr].ppcReg = -1;
|
||||||
OpArg newLoc = GetDefaultLocation(i);
|
OpArg newLoc = GetDefaultLocation(i);
|
||||||
MOVAPD(newLoc, xr);
|
MOVAPD(newLoc, xr);
|
||||||
regs[i].location = newLoc;
|
regs[i].location = newLoc;
|
||||||
regs[i].away = false;
|
regs[i].away = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// _assert_msg_(DYNA_REC,0,"already stored");
|
// _assert_msg_(DYNA_REC,0,"already stored");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::Flush(FlushMode mode)
|
void RegCache::Flush(FlushMode mode)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUMXREGS; i++) {
|
for (int i = 0; i < NUMXREGS; i++) {
|
||||||
if (xlocks[i])
|
if (xlocks[i])
|
||||||
PanicAlert("Somone forgot to unlock X64 reg %i.", i);
|
PanicAlert("Somone forgot to unlock X64 reg %i.", i);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 32; i++)
|
for (int i = 0; i < 32; i++)
|
||||||
{
|
{
|
||||||
if (locks[i])
|
if (locks[i])
|
||||||
{
|
{
|
||||||
PanicAlert("Somebody forgot to unlock PPC reg %i.", i);
|
PanicAlert("Somebody forgot to unlock PPC reg %i.", i);
|
||||||
}
|
}
|
||||||
if (regs[i].away)
|
if (regs[i].away)
|
||||||
{
|
{
|
||||||
if (regs[i].location.IsSimpleReg())
|
if (regs[i].location.IsSimpleReg())
|
||||||
{
|
{
|
||||||
X64Reg xr = RX(i);
|
X64Reg xr = RX(i);
|
||||||
StoreFromX64(i);
|
StoreFromX64(i);
|
||||||
xregs[xr].dirty = false;
|
xregs[xr].dirty = false;
|
||||||
}
|
}
|
||||||
else if (regs[i].location.IsImm())
|
else if (regs[i].location.IsImm())
|
||||||
{
|
{
|
||||||
StoreFromX64(i);
|
StoreFromX64(i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %i", i);
|
_assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %i", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue