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:
bushing 2008-12-08 05:30:24 +00:00
parent 901fe7c00f
commit 49cfded60b
177 changed files with 53968 additions and 53968 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 = &sections[sections.size() - 1]; section = &sections[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;
} }
*/ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(&section, spincount); InitializeCriticalSectionAndSpinCount(&section, spincount);
} }
else else
{ {
InitializeCriticalSection(&section); InitializeCriticalSection(&section);
} }
} }
CriticalSection::~CriticalSection() CriticalSection::~CriticalSection()
{ {
DeleteCriticalSection(&section); DeleteCriticalSection(&section);
} }
void CriticalSection::Enter() void CriticalSection::Enter()
{ {
EnterCriticalSection(&section); EnterCriticalSection(&section);
} }
bool CriticalSection::TryEnter() bool CriticalSection::TryEnter()
{ {
return(TryEnterCriticalSection(&section) ? true : false); return(TryEnterCriticalSection(&section) ? true : false);
} }
void CriticalSection::Leave() void CriticalSection::Leave()
{ {
LeaveCriticalSection(&section); LeaveCriticalSection(&section);
} }
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

View File

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

View File

@ -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(&ltime); time(&ltime);
return((u64)ltime); return((u64)ltime);
} }
} // end of namespace Common } // end of namespace Common

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 = &sections[i]; Elf32_Shdr *s = &sections[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;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,2 +1,2 @@
#include "Host.h" #include "Host.h"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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