Initial megacommit.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard
2008-07-12 17:40:22 +00:00
parent a3be5d89ae
commit 775dc8a9c0
1920 changed files with 734652 additions and 0 deletions

1237
Source/Core/Core/Core.vcproj Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,603 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "StringUtil.h"
#include "../HLE/HLE.h"
#include "../PowerPC/PowerPC.h"
#include "../PowerPC/PPCAnalyst.h"
#include "../Core.h"
#include "../HW/HW.h"
#include "../HW/EXI_DeviceIPL.h"
#include "../HW/Memmap.h"
#include "../HW/PeripheralInterface.h"
#include "../HW/DVDInterface.h"
#include "../HW/VideoInterface.h"
#include "../HW/CPU.h"
#include "../Debugger/Debugger_SymbolMap.h"
#include "../Debugger/Debugger_BreakPoints.h"
#include "Boot_DOL.h"
#include "Boot.h"
#include "../Host.h"
#include "../VolumeHandler.h"
#include "../PatchEngine.h"
#include "../Host.h"
#include "../MemTools.h"
#include "MappedFile.h"
#include "VolumeCreator.h"
bool CBoot::Boot_BIN(const std::string& _rFilename)
{
Common::IMappedFile* pFile = Common::IMappedFile::CreateMappedFile();
if (pFile->Open(_rFilename.c_str()))
{
u8* pData = pFile->Lock(0, pFile->GetSize());
Memory::WriteBigEData(pData, 0x80000000, (u32)pFile->GetSize());
pFile->Unlock(pData);
pFile->Close();
}
delete pFile;
return true;
}
void WrapRunFunction(void*)
{
while (PC != 0x00)
{
CCPU::SingleStep();
}
}
void WrapRunFunction2(void*)
{
while (PC != 0x00)
{
PowerPC::SingleStep();
}
}
void CBoot::RunFunction(u32 _iAddr, bool _bUseDebugger)
{
PC = _iAddr;
LR = 0x00;
if (_bUseDebugger)
{
CCPU::Break();
//EMM::Wrap(WrapRunFunction,0);
WrapRunFunction(0);
}
else
{
//EMM::Wrap(WrapRunFunction2,0);
WrapRunFunction2(0);
}
}
// __________________________________________________________________________________________________
//
// BIOS HLE:
// copy the apploader to 0x81200000
// execute the apploader
//
void CBoot::EmulatedBIOS(bool _bDebug)
{
LOG(BOOT, "Faking GC BIOS...");
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
//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, 0x80000800); // write default FPU Handler: rfi
Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
//
Memory::Write_U32(0xc2339f3d, 0x8000001C); //game disc
Memory::Write_U32(0x0D15EA5E, 0x80000020); //funny magic word for normal boot
Memory::Write_U32(0x01800000, 0x80000028); // Physical Memory Size
// Memory::Write_U32(0x00000003, 0x8000002C); // Console type - retail
Memory::Write_U32(0x10000006, 0x8000002C); // DevKit
Memory::Write_U32(((1 & 0x3f) << 26) | 2, 0x81300000); // HLE OSReport for Apploader
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
u32 iAppLoaderOffset = 0x2440; // 0x1c40;
// Load Apploader to Memory
u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14);
if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
return;
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
//call iAppLoaderEntry
LOG(MASTER_LOG, "Call iAppLoaderEntry");
u32 iAppLoaderFuncAddr = 0x80003100;
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
RunFunction(iAppLoaderEntry, _bDebug);
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
// iAppLoaderInit
LOG(MASTER_LOG, "Call iAppLoaderInit");
PowerPC::ppcState.gpr[3] = 0x81300000;
RunFunction(iAppLoaderInit, _bDebug);
// iAppLoaderMain
LOG(MASTER_LOG, "Call iAppLoaderMain");
do
{
PowerPC::ppcState.gpr[3] = 0x81300004;
PowerPC::ppcState.gpr[4] = 0x81300008;
PowerPC::ppcState.gpr[5] = 0x8130000c;
RunFunction(iAppLoaderMain, _bDebug);
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c);
LOG(MASTER_LOG, "DVDRead: offset: %08x memOffse: %08x length: %i", iDVDOffset, iRamAddress, iLength);
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
} while(PowerPC::ppcState.gpr[3] != 0x00);
// iAppLoaderClose
LOG(MASTER_LOG, "call iAppLoaderClose");
RunFunction(iAppLoaderClose, _bDebug);
// Load patches and run startup patches
std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
PatchEngine_LoadPatches(gameID.c_str());
PatchEngine_ApplyLoadPatches();
PowerPC::ppcState.DebugCount = 0;
// return
PC = PowerPC::ppcState.gpr[3];
//
// --- preinit some stuff from bios ---
//
// Bus Clock Speed
Memory::Write_U32(0x09a7ec80, 0x800000F8);
Memory::Write_U32(0x1cf7c580, 0x800000FC);
// fake the VI Init of the BIOS
Memory::Write_U32(Core::g_CoreStartupParameter.bNTSC ? 0 : 1, 0x800000CC);
// preset time
Memory::Write_U32(CEXIIPL::GetGCTime(), 0x800030D8);
}
// __________________________________________________________________________________________________
//
// BIOS HLE:
// copy the apploader to 0x81200000
// execute the apploader
//
bool CBoot::EmulatedBIOS_Wii(bool _bDebug)
{
if (!VolumeHandler::IsValid())
{
LOG(MASTER_LOG, "Invalid volume");
return false;
}
LOG(BOOT, "Faking Wii BIOS...");
// load settings.txt
{
std::string filename;
switch(VolumeHandler::GetVolume()->GetCountry())
{
case DiscIO::IVolume::COUNTRY_JAP:
filename = "wii/setting-jpn.txt";
break;
case DiscIO::IVolume::COUNTRY_USA:
filename = "wii/setting-usa.txt";
break;
default:
filename = "wii/setting-eur.txt";
break;
}
FILE* pTmp = fopen(filename.c_str(), "rb");
if (!pTmp)
{
LOG(MASTER_LOG, "Cant find setting file");
return false;
}
fread(Memory::GetPointer(0x3800), 256, 1, pTmp);
fclose(pTmp);
}
// int global vars
{
Memory::Write_U32(0x00000000, 0x000030f0); // apploader
Memory::Write_U16(0x0113, 0x0000315e); // apploader
Memory::Write_U32(0x5d1c9ea3, 0x00000018); // magic word it is a wii disc
Memory::Write_U32(0x01800000, 0x00000028);
Memory::Write_U32(0x04000000, 0x00003118);
Memory::Write_U32(0x00000023, 0x0000002c);
Memory::Write_U32(0x00000000, 0x000030dc); // OSTime
Memory::Write_U32(0x00000000, 0x000030d8); // OSTime
Memory::Write_U32(0x00000000, 0x0000310c); // OSInit
Memory::Write_U32(0x90000800, 0x00003124); // OSInit - MEM2 low
Memory::Write_U32(0x933e0000, 0x00003128); // OSInit - MEM2 high
Memory::Write_U32(0x933e0000, 0x00003130); // IPC MEM2 low
Memory::Write_U32(0x93400000, 0x00003134); // IPC MEM2 high
Memory::Write_U32(0x38a00040, 0x00000060); // exception init
Memory::Write_U16(0x0000, 0x000030e6); // console type
Memory::Write_U32(0x00000011, 0x00003138); // console type
Memory::Write_U32(0x0e7be2c0, 0x000000f8); // EXI
Memory::Write_U32(0x00000000, 0x000030c0); // EXI
Memory::Write_U32(0x00000000, 0x000030c4); // EXI
Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init
Memory::Write_U32(0x01800000, 0x00003104); // BAT
Memory::Write_U32(0x01800000, 0x00003100); // BAT
Memory::Write_U32(0x04000000, 0x0000311c); // BAT
Memory::Write_U32(0x93400000, 0x00003120); // BAT
Memory::Write_U8(0x80, 0x0000315c); // OSInit
Memory::Write_U8(0x00, 0x00000006); // DVDInit
Memory::Write_U8(0x00, 0x00000007); // DVDInit
Memory::Write_U32(0x00000005, 0x000000cc); // VIInit
Memory::Write_U16(0x0000, 0x000030e0); // PADInit
// app
VolumeHandler::ReadToPtr(Memory::GetPointer(0x3180), 0, 4);
Memory::Write_U8(0x80, 0x00003184);
}
// apploader
{
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
m_MSR.FP = 1;
//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, 0x80000800); // write default FPU Handler: rfi
Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
Memory::Write_U32(((1 & 0x3f) << 26) | 2, 0x81300000); // HLE OSReport for Apploader
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
u32 iAppLoaderOffset = 0x2440; // 0x1c40;
// Load Apploader to Memory
u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14);
if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
{
LOG(BOOT, "Invalid apploader. WTF.");
return false;
}
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
//call iAppLoaderEntry
LOG(BOOT, "Call iAppLoaderEntry");
u32 iAppLoaderFuncAddr = 0x80004000;
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
RunFunction(iAppLoaderEntry, _bDebug);
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
// iAppLoaderInit
LOG(BOOT, "Call iAppLoaderInit");
PowerPC::ppcState.gpr[3] = 0x81300000;
RunFunction(iAppLoaderInit, _bDebug);
// iAppLoaderMain
LOG(BOOT, "Call iAppLoaderMain");
do
{
PowerPC::ppcState.gpr[3] = 0x81300004;
PowerPC::ppcState.gpr[4] = 0x81300008;
PowerPC::ppcState.gpr[5] = 0x8130000c;
RunFunction(iAppLoaderMain, _bDebug);
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c) << 2;
LOG(BOOT, "DVDRead: offset: %08x memOffse: %08x length: %i", iDVDOffset, iRamAddress, iLength);
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
} while(PowerPC::ppcState.gpr[3] != 0x00);
// iAppLoaderClose
LOG(BOOT, "call iAppLoaderClose");
RunFunction(iAppLoaderClose, _bDebug);
// Load patches and run startup patches
std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
PatchEngine_LoadPatches(gameID.c_str());
// return
PC = PowerPC::ppcState.gpr[3];
}
PowerPC::ppcState.DebugCount = 0;
return true;
}
void CBoot::UpdateDebugger_MapLoaded(const char *_gameID)
{
HLE::PatchFunctions(_gameID);
Debugger::AnalyzeBackwards();
Host_NotifyMapLoaded();
Host_UpdateMemoryView();
}
bool CBoot::LoadMapFromFilename(const std::string &_rFilename, const char *_gameID)
{
if (_rFilename.size() == 0)
return false;
std::string strDriveDirectory, strFilename;
SplitPath(_rFilename, &strDriveDirectory, &strFilename, NULL);
std::string strFullfilename(strFilename + _T(".map"));
std::string strMapFilename;
BuildCompleteFilename(strMapFilename, strDriveDirectory, strFullfilename);
bool success = false;
if (!Debugger::LoadSymbolMap(strMapFilename.c_str()))
{
if (_gameID != NULL)
{
BuildCompleteFilename(strMapFilename, _T("maps"), std::string(_gameID) + _T(".map"));
success = Debugger::LoadSymbolMap(strMapFilename.c_str());
}
}
else
{
success = true;
}
if (success)
UpdateDebugger_MapLoaded();
return success;
}
bool CBoot::Load_BIOS(const std::string& _rBiosFilename)
{
bool bResult = false;
Common::IMappedFile* pFile = Common::IMappedFile::CreateMappedFile();
if (pFile->Open(_rBiosFilename.c_str()))
{
if (pFile->GetSize() >= 1024*1024*2)
{
u32 CopySize = (u32)pFile->GetSize() - 0x820;
u8* pData = pFile->Lock(0x820, CopySize);
Memory::WriteBigEData(pData, 0x81300000, CopySize);
pFile->Unlock(pData);
pFile->Close();
PC = 0x81300000;
bResult = true;
}
}
delete pFile;
return bResult;
}
bool CBoot::BootUp(const SCoreStartupParameter& _StartupPara)
{
const bool bDebugIsoBootup = false;
VideoInterface::PreInit(_StartupPara.bNTSC);
switch(_StartupPara.m_BootType)
{
// GCM
// ===================================================================================
case SCoreStartupParameter::BOOT_ISO:
{
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(_StartupPara.m_strFilename);
if (pVolume == NULL)
break;
bool isoWii = DiscIO::IsVolumeWiiDisc(*pVolume);
if (isoWii != Core::GetStartupParameter().bWii)
{
PanicAlert("Warning - starting ISO in wrong console mode!");
}
char gameID[7];
memcpy(gameID, pVolume->GetUniqueID().c_str(), 6);
gameID[6] = 0;
// setup the map from ISOFile ID
VolumeHandler::SetVolumeName(_StartupPara.m_strFilename);
DVDInterface::SetDiscInside(true);
if (_StartupPara.bHLEBios)
{
if (!VolumeHandler::IsWii())
EmulatedBIOS(bDebugIsoBootup);
else
{
Core::g_CoreStartupParameter.bWii = true;
EmulatedBIOS_Wii(bDebugIsoBootup);
}
}
else
{
if (!Load_BIOS(_StartupPara.m_strBios))
{
// fails to load a BIOS so HLE it
if (!VolumeHandler::IsWii())
EmulatedBIOS(bDebugIsoBootup);
else
{
Core::g_CoreStartupParameter.bWii = true;
EmulatedBIOS_Wii(bDebugIsoBootup);
}
}
}
if (LoadMapFromFilename(_StartupPara.m_strFilename, gameID))
{
HLE::PatchFunctions(gameID);
}
else
{
#if defined(_DEBUG) || defined(DEBUGFAST)
//PPCAnalyst::FindFunctions(0x81300000,0x81400000);
#if 0
PPCAnalyst::FindFunctions(0x80003100,0x80200000);
PPCAnalyst::LoadFuncDB("data/totaldb.dsy");
PPCAnalyst::UseFuncDB();
#endif
#endif
Debugger::GetFromAnalyzer();
UpdateDebugger_MapLoaded();
}
}
break;
// DOL
// ===================================================================================
case SCoreStartupParameter::BOOT_DOL:
{
CDolLoader dolLoader(_StartupPara.m_strFilename.c_str());
PC = dolLoader.GetEntryPoint();
#ifdef _DEBUG
if (!LoadMapFromFilename(_StartupPara.m_strFilename))
{
PPCAnalyst::FindFunctions(0x80003100,0x80400000);
PPCAnalyst::LoadFuncDB("data/totaldb.dsy");
PPCAnalyst::UseFuncDB();
Debugger::GetFromAnalyzer();
UpdateDebugger_MapLoaded();
}
#endif
}
break;
// ELF
// ===================================================================================
case SCoreStartupParameter::BOOT_ELF:
{
bool elfWii = IsElfWii(_StartupPara.m_strFilename.c_str());
if (elfWii != Core::GetStartupParameter().bWii)
{
PanicAlert("Warning - starting ELF in wrong console mode!");
}
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM);
if (elfWii)
{
if (VolumeHandler::IsWii() && (!_StartupPara.m_strDefaultGCM.empty()))
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM.c_str());
EmulatedBIOS_Wii(false);
}
else
{
if (!VolumeHandler::IsWii() && !_StartupPara.m_strDefaultGCM.empty())
{
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM.c_str());
EmulatedBIOS(false);
}
}
Boot_ELF(_StartupPara.m_strFilename.c_str());
UpdateDebugger_MapLoaded();
CBreakPoints::AddAutoBreakpoints();
}
break;
// BIN
// ===================================================================================
case SCoreStartupParameter::BOOT_BIN:
{
if (!_StartupPara.m_strDefaultGCM.empty())
{
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM.c_str());
EmulatedBIOS(false);
}
Boot_BIN(_StartupPara.m_strFilename);
LoadMapFromFilename(_StartupPara.m_strFilename);
}
break;
// BIOS
// ===================================================================================
case SCoreStartupParameter::BOOT_BIOS:
{
DVDInterface::SetDiscInside(false);
if (Load_BIOS(_StartupPara.m_strBios))
{
if (!LoadMapFromFilename(_StartupPara.m_strFilename))
{
PPCAnalyst::FindFunctions(0x81300000,0x81400000);
PPCAnalyst::LoadFuncDB("data/totaldb.dsy");
PPCAnalyst::UseFuncDB();
Debugger::GetFromAnalyzer();
UpdateDebugger_MapLoaded();
}
}
else
{
return false;
}
}
break;
default:
{
PanicAlert("Tried to load an unknown file type.");
return false;
}
}
Host_UpdateLogDisplay();
return true;
}

View File

@ -0,0 +1,62 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _BOOT_H
#define _BOOT_H
#include <string>
#include "Common.h"
#include "../CoreParameter.h"
class CBoot
{
public:
enum TBootFileType
{
BOOT_ERROR,
BOOT_DOL,
BOOT_ELF,
BOOT_BIN,
BOOT_ISO,
BOOT_BIOS
};
static bool BootUp(const SCoreStartupParameter& _StartupPara);
static bool IsElfWii(const char *filename);
private:
enum { BIOS_SIZE = 2*1024*1024 };
static char gameID[7];
static void RunFunction(u32 _iAddr, bool _bUseDebugger);
static void UpdateDebugger_MapLoaded(const char* _gameID = NULL);
static bool LoadMapFromFilename(const std::string& _rFilename, const char* _gameID = NULL);
static bool Boot_ELF(const char *filename);
static bool Boot_BIN(const std::string& _rFilename);
static void EmulatedBIOS(bool _bDebug);
static bool EmulatedBIOS_Wii(bool _bDebug);
static bool Load_BIOS(const std::string& _rBiosFilename);
};
#endif

View File

@ -0,0 +1,80 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Boot_DOL.h"
#include "../HW/Memmap.h"
CDolLoader::CDolLoader(const char* _szFilename) : m_bInit(false)
{
// try to open file
FILE* pStream = fopen(_szFilename, "rb");
if (pStream)
{
fread(&m_dolheader, 1, sizeof(SDolHeader), pStream);
// swap memory
u32* p = (u32*)&m_dolheader;
for (int i=0; i<(sizeof(SDolHeader)>>2); i++)
p[i] = Common::swap32(p[i]);
// load all text (code) sections
for(int i=0; i<DOL_NUM_TEXT; i++)
{
if(m_dolheader.textOffset[i] != 0)
{
u8* pTemp = new u8[m_dolheader.textSize[i]];
fseek(pStream, m_dolheader.textOffset[i], SEEK_SET);
fread(pTemp, 1, m_dolheader.textSize[i], pStream);
for (u32 num = 0; num < m_dolheader.textSize[i]; num++)
Memory::Write_U8(pTemp[num], m_dolheader.textAddress[i] + num);
delete [] pTemp;
}
}
// load all data sections
for(int i=0; i<DOL_NUM_DATA; i++)
{
if(m_dolheader.dataOffset[i] != 0)
{
u8* pTemp = new u8[m_dolheader.dataSize[i]];
fseek(pStream, m_dolheader.dataOffset[i], SEEK_SET);
fread(pTemp, 1, m_dolheader.dataSize[i], pStream);
for (u32 num = 0; num < m_dolheader.dataSize[i]; num++)
Memory::Write_U8(pTemp[num], m_dolheader.dataAddress[i] + num);
delete [] pTemp;
}
}
//TODO - we know where there is code, and where there is data
//Make use of this!
fclose(pStream);
m_bInit = true;
}
}
u32 CDolLoader::GetEntryPoint()
{
return m_dolheader.entryPoint;
}

View File

@ -0,0 +1,54 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _BOOT_DOL_H
#define _BOOT_DOL_H
#include "Common.h"
class CDolLoader
{
public:
CDolLoader(const char* _szFilename);
u32 GetEntryPoint();
private:
enum
{
DOL_NUM_TEXT = 7,
DOL_NUM_DATA = 11
};
struct SDolHeader
{
u32 textOffset[DOL_NUM_TEXT];
u32 dataOffset[DOL_NUM_DATA];
u32 textAddress[DOL_NUM_TEXT];
u32 dataAddress[DOL_NUM_DATA];
u32 textSize[DOL_NUM_TEXT];
u32 dataSize[DOL_NUM_DATA];
u32 bssAddress;
u32 bssSize;
u32 entryPoint;
u32 padd[7];
};
SDolHeader m_dolheader;
bool m_bInit;
};
#endif

View File

@ -0,0 +1,48 @@
#include "../PowerPC/PowerPC.h"
#include "Boot.h"
#include "Boot_ELF.h"
#include "ElfReader.h"
#include "MappedFile.h"
bool CBoot::IsElfWii(const char *filename)
{
Common::IMappedFile *mapfile = Common::IMappedFile::CreateMappedFile();
mapfile->Open(filename);
u8 *ptr = mapfile->Lock(0, mapfile->GetSize());
u8 *mem = new u8[(size_t)mapfile->GetSize()];
memcpy(mem, ptr, (size_t)mapfile->GetSize());
mapfile->Unlock(ptr);
mapfile->Close();
ElfReader reader(mem);
// TODO: Find a more reliable way to distinguish.
bool isWii = reader.GetEntryPoint() >= 0x80004000;
delete [] mem;
return isWii;
}
bool CBoot::Boot_ELF(const char *filename)
{
Common::IMappedFile *mapfile = Common::IMappedFile::CreateMappedFile();
mapfile->Open(filename);
u8 *ptr = mapfile->Lock(0, mapfile->GetSize());
u8 *mem = new u8[(size_t)mapfile->GetSize()];
memcpy(mem, ptr, (size_t)mapfile->GetSize());
mapfile->Unlock(ptr);
mapfile->Close();
ElfReader reader(mem);
reader.LoadInto(0x80000000);
if (!reader.LoadSymbols())
{
LoadMapFromFilename(filename);
}
delete [] mem;
PC = reader.GetEntryPoint();
return true;
}

View File

@ -0,0 +1 @@
#pragma once

View File

@ -0,0 +1,266 @@
#include <string>
#include "Common.h"
#include "../Debugger/Debugger_SymbolMap.h"
#include "../HW/Memmap.h"
#include "ElfReader.h"
//#include "../PSP/HLE/sceKernelMemory.h"
void bswap(Elf32_Word &w) {w = Common::swap32(w);}
void bswap(Elf32_Half &w) {w = Common::swap16(w);}
void byteswapHeader(Elf32_Ehdr &ELF_H)
{
bswap(ELF_H.e_type);
bswap(ELF_H.e_machine);// = _byteswap_ushort(ELF_H.e_machine);
bswap(ELF_H.e_ehsize);// = _byteswap_ushort(ELF_H.e_ehsize);
bswap(ELF_H.e_phentsize);// = _byteswap_ushort(ELF_H.e_phentsize);
bswap(ELF_H.e_phnum);// = _byteswap_ushort(ELF_H.e_phnum);
bswap(ELF_H.e_shentsize);// = _byteswap_ushort(ELF_H.e_shentsize);
bswap(ELF_H.e_shnum);// = _byteswap_ushort(ELF_H.e_shnum);
bswap(ELF_H.e_shstrndx);//= _byteswap_ushort(ELF_H.e_shstrndx);
bswap(ELF_H.e_version);// = _byteswap_ulong(ELF_H.e_version );
bswap(ELF_H.e_entry);// = _byteswap_ulong(ELF_H.e_entry );
bswap(ELF_H.e_phoff);// = _byteswap_ulong(ELF_H.e_phoff );
bswap(ELF_H.e_shoff);// = _byteswap_ulong(ELF_H.e_shoff );
bswap(ELF_H.e_flags);
}
void byteswapSegment(Elf32_Phdr &sec)
{
bswap(sec.p_align);
bswap(sec.p_filesz);
bswap(sec.p_flags);
bswap(sec.p_memsz);
bswap(sec.p_offset);
bswap(sec.p_paddr);
bswap(sec.p_vaddr);
bswap(sec.p_type);
}
void byteswapSection(Elf32_Shdr &sec)
{
bswap(sec.sh_addr);
bswap(sec.sh_addralign);
bswap(sec.sh_entsize);
bswap(sec.sh_flags);
bswap(sec.sh_info);
bswap(sec.sh_link);
bswap(sec.sh_name);
bswap(sec.sh_offset);
bswap(sec.sh_size);
bswap(sec.sh_type);
}
ElfReader::ElfReader(void *ptr)
{
base = (char*)ptr;
base32 = (u32 *)ptr;
header = (Elf32_Ehdr*)ptr;
byteswapHeader(*header);
segments = (Elf32_Phdr *)(base + header->e_phoff);
sections = (Elf32_Shdr *)(base + header->e_shoff);
for (int i = 0; i < GetNumSegments(); i++)
{
byteswapSegment(segments[i]);
}
for (int i = 0; i < GetNumSections(); i++)
{
byteswapSection(sections[i]);
}
entryPoint = header->e_entry;
}
const char *ElfReader::GetSectionName(int section)
{
if (sections[section].sh_type == SHT_NULL)
return 0;
int nameOffset = sections[section].sh_name;
char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx);
if (ptr)
return ptr + nameOffset;
else
return 0;
}
void addrToHiLo(u32 addr, u16 &hi, s16 &lo)
{
lo = (addr & 0xFFFF);
u32 naddr = addr - lo;
hi = naddr>>16;
u32 test = (hi<<16) + lo;
if (test != addr)
{
Crash();
}
}
bool ElfReader::LoadInto(u32 vaddr)
{
LOG(MASTER_LOG,"String section: %i", header->e_shstrndx);
// sectionOffsets = new u32[GetNumSections()];
// sectionAddrs = new u32[GetNumSections()];
// Should we relocate?
bRelocate = (header->e_type != ET_EXEC);
if (bRelocate)
{
LOG(MASTER_LOG,"Relocatable module");
entryPoint += vaddr;
}
else
{
LOG(MASTER_LOG,"Prerelocated executable");
}
LOG(MASTER_LOG,"%i segments:", header->e_phnum);
// First pass : Get the bits into RAM
u32 segmentVAddr[32];
u32 baseAddress = bRelocate?vaddr:0;
for (int i=0; i<header->e_phnum; 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);
if (p->p_type == PT_LOAD)
{
segmentVAddr[i] = baseAddress + p->p_vaddr;
u32 writeAddr = segmentVAddr[i];
u8 *src = GetSegmentPtr(i);
u8 *dst = Memory::GetPointer(writeAddr);
u32 srcSize = p->p_filesz;
u32 dstSize = p->p_memsz;
//PSPHLE::userMemory.AllocAt(writeAddr, dstSize);
//memcpy(dst, src, srcSize);
u32 *s = (u32*)src;
u32 *d = (u32*)dst;
//TODO : remove byteswapping
for (int i=0; i<(int)srcSize/4+1; i++)
{
*d++ = /*_byteswap_ulong*/(*s++);
}
if (srcSize < dstSize)
{
//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,"%i sections:", header->e_shnum);
for (int i=0; i<GetNumSections(); i++)
{
Elf32_Shdr *s = &sections[i];
const char *name = GetSectionName(i);
u32 writeAddr = s->sh_addr + baseAddress;
sectionOffsets[i] = writeAddr - vaddr;
sectionAddrs[i] = writeAddr;
if (s->sh_flags & SHF_ALLOC)
{
LOG(MASTER_LOG,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, s->sh_size);
}
else
{
LOG(MASTER_LOG,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, s->sh_size, s->sh_flags);
}
}
*/
LOG(MASTER_LOG,"Done.");
return true;
}
SectionID ElfReader::GetSectionByName(const char *name, int firstSection)
{
for (int i = firstSection; i < header->e_shnum; i++)
{
const char *secname = GetSectionName(i);
if (secname != 0 && strcmp(name, secname) == 0)
{
return i;
}
}
return -1;
}
bool ElfReader::LoadSymbols()
{
bool hasSymbols = false;
SectionID sec = GetSectionByName(".symtab");
if (sec != -1)
{
int stringSection = sections[sec].sh_link;
const char *stringBase = (const char*)GetSectionDataPtr(stringSection);
//We have a symbol table!
Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
for (int sym = 0; sym<numSymbols; sym++)
{
int size = Common::swap32(symtab[sym].st_size);
if (size == 0)
continue;
// int bind = symtab[sym].st_info >> 4;
int type = symtab[sym].st_info & 0xF;
int sectionIndex = Common::swap16(symtab[sym].st_shndx);
int value = Common::swap32(symtab[sym].st_value);
const char *name = stringBase + Common::swap32(symtab[sym].st_name);
if (bRelocate)
value += sectionAddrs[sectionIndex];
Debugger::ESymbolType symtype = Debugger::ST_DATA;
switch (type)
{
case STT_OBJECT:
symtype = Debugger::ST_DATA; break;
case STT_FUNC:
symtype =Debugger:: ST_FUNCTION; break;
default:
continue;
}
//host->AddSymbol(name, value, size, symtype);
Debugger::AddSymbol(
Debugger::CSymbol(value, size, symtype, name));
hasSymbols = true;
//...
}
}
return hasSymbols;
}

View File

@ -0,0 +1,85 @@
#ifndef _ELFREADER_H
#define _ELFREADER_H
#include "ElfTypes.h"
enum KnownElfTypes
{
KNOWNELF_PSP = 0,
KNOWNELF_DS = 1,
KNOWNELF_GBA = 2,
KNOWNELF_GC = 3,
};
typedef int SectionID;
class ElfReader
{
char *base;
u32 *base32;
Elf32_Ehdr *header;
Elf32_Phdr *segments;
Elf32_Shdr *sections;
u32 *sectionOffsets;
u32 *sectionAddrs;
bool bRelocate;
u32 entryPoint;
public:
ElfReader(void *ptr);
~ElfReader()
{
}
u32 Read32(int off)
{
return base32[off>>2];
}
// Quick accessors
ElfType GetType() { return (ElfType)(header->e_type); }
ElfMachine GetMachine() { return (ElfMachine)(header->e_machine); }
u32 GetEntryPoint() { return entryPoint; }
u32 GetFlags() { return (u32)(header->e_flags); }
int GetNumSegments() { return (int)(header->e_phnum); }
int GetNumSections() { return (int)(header->e_shnum); }
const char *GetSectionName(int section);
u8 *GetPtr(int offset)
{
return (u8*)base + offset;
}
u8 *GetSectionDataPtr(int section)
{
if (section < 0 || section >= header->e_shnum)
return 0;
if (sections[section].sh_type != SHT_NOBITS)
return GetPtr(sections[section].sh_offset);
else
return 0;
}
u8 *GetSegmentPtr(int segment)
{
return GetPtr(segments[segment].p_offset);
}
u32 GetSectionAddr(SectionID section) {return sectionAddrs[section];}
int GetSectionSize(SectionID section)
{
return sections[section].sh_size;
}
SectionID GetSectionByName(const char *name, int firstSection=0); //-1 for not found
bool DidRelocate() {
return bRelocate;
}
// More indepth stuff:)
bool LoadInto(u32 vaddr);
bool LoadSymbols();
};
#endif

View File

@ -0,0 +1,281 @@
#ifndef _ELFTYPES_H
#define _ELFTYPES_H
// ELF Header Constants
// File type
enum ElfType
{
ET_NONE =0,
ET_REL =1,
ET_EXEC =2,
ET_DYN =3,
ET_CORE =4,
ET_LOPROC =0xFF00,
ET_HIPROC =0xFFFF,
};
// Machine/Architecture
enum ElfMachine
{
EM_NONE =0,
EM_M32 =1,
EM_SPARC =2,
EM_386 =3,
EM_68K =4,
EM_88K =5,
EM_860 =7,
EM_MIPS =8
};
// File version
#define EV_NONE 0
#define EV_CURRENT 1
// Identification index
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_PAD 7
#define EI_NIDENT 16
// Magic number
#define ELFMAG0 0x7F
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
// File class
#define ELFCLASSNONE 0
#define ELFCLASS32 1
#define ELFCLASS64 2
// Encoding
#define ELFDATANONE 0
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2
/////////////////////
// Sections constants
// Section indexes
#define SHN_UNDEF 0
#define SHN_LORESERVE 0xFF00
#define SHN_LOPROC 0xFF00
#define SHN_HIPROC 0xFF1F
#define SHN_ABS 0xFFF1
#define SHN_COMMON 0xFFF2
#define SHN_HIRESERVE 0xFFFF
// Section types
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_LOPROC 0x70000000
#define SHT_HIPROC 0x7FFFFFFF
#define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xFFFFFFFF
// Custom section types
#define SHT_PSPREL 0x700000a0
// Section flags
enum ElfSectionFlags
{
SHF_WRITE =0x1,
SHF_ALLOC =0x2,
SHF_EXECINSTR =0x4,
SHF_MASKPROC =0xF0000000,
};
// Symbol binding
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STB_LOPROC 13
#define STB_HIPROC 15
// Symbol types
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_LOPROC 13
#define STT_HIPROC 15
// Undefined name
#define STN_UNDEF 0
// Relocation types
#define R_386_NONE 0
#define R_386_32 1
#define R_386_PC32 2
#define R_386_GOT32 3
#define R_386_PLT32 4
#define R_386_COPY 5
#define R_386_GLOB_DAT 6
#define R_386_JMP_SLOT 7
#define R_386_RELATIVE 8
#define R_386_GOTOFF 9
#define R_386_GOTPC 10
// Segment types
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7FFFFFFF
// Segment flags
#define PF_X 1
#define PF_W 2
#define PF_R 4
// Dynamic Array Tags
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
#define DT_FINI 13
#define DT_SONAME 14
#define DT_RPATH 15
#define DT_SYMBOLIC 16
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7FFFFFFF
typedef unsigned int Elf32_Addr;
typedef unsigned short Elf32_Half;
typedef unsigned int Elf32_Off;
typedef signed int Elf32_Sword;
typedef unsigned int Elf32_Word;
// ELF file header
struct Elf32_Ehdr
{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
};
// Section header
struct Elf32_Shdr
{
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
};
// Segment header
struct Elf32_Phdr
{
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
};
// Symbol table entry
struct Elf32_Sym
{
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
};
#define ELF32_ST_BIND(i) ((i)>>4)
#define ELF32_ST_TYPE(i) ((i)&0xf)
#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
// Relocation entries
struct Elf32_Rel
{
Elf32_Addr r_offset;
Elf32_Word r_info;
};
struct Elf32_Rela
{
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Sword r_addend;
};
#define ELF32_R_SYM(i) ((i)>>8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t))
struct Elf32_Dyn
{
Elf32_Sword d_tag;
union
{
Elf32_Word d_val;
Elf32_Addr d_ptr;
} d_un;
};
#endif

View File

@ -0,0 +1,176 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <iostream>
#include "string.h"
#include "Common.h"
#include "Thread.h"
#include "HW/Memmap.h"
#include "PowerPC/PPCAnalyst.h"
#include "PowerPC/PPCTables.h"
#include "Console.h"
#include "CoreTiming.h"
#include "Core.h"
#include "PowerPC/Jit64/JitCache.h"
#include "PowerPCDisasm.h"
#define CASE(x) else if (memcmp(cmd, x,4*sizeof(TCHAR))==0)
#define CASE1(x) if (memcmp(cmd, x,2*sizeof(TCHAR))==0)
Common::Thread *cons_thread;
/*
THREAD_RETURN ConsoleThreadFunc(void *) {
printf("Welcome to the console thread!\n\n");
while (true) {
std::string command;
getline(std::cin, command);
Console_Submit(command.c_str());
}
}
void StartConsoleThread() {
cons_thread = new Common::Thread(ConsoleThreadFunc, 0);
}*/
void Console_Submit(const char *cmd)
{
CASE1("jits")
{
#ifdef _M_X64
Jit64::PrintStats();
#endif
}
CASE1("r")
{
Core::StartTrace(false);
LOG(CONSOLE, "read tracing started.");
}
CASE1("w")
{
Core::StartTrace(true);
LOG(CONSOLE, "write tracing started.");
}
CASE("scan")
{
//LOG(CONSOLE,"test1");
PPCAnalyst::FindFunctions(0x80003100, 0x80400000);
}
CASE("trans")
{
TCHAR temp[256];
u32 addr;
sscanf(cmd, "%s %08x", temp, &addr);
if (addr!=0)
{
u32 EA = Memory::CheckDTLB(addr, Memory::FLAG_NO_EXCEPTION);
LOG(CONSOLE, "EA 0x%08x to 0x%08x", addr, EA);
}
else
{
LOG(CONSOLE, "Syntax: trans ADDR");
}
}
CASE("call")
{
TCHAR temp[256];
u32 addr;
sscanf(cmd, "%s %08x", temp, &addr);
if (addr!=0)
{
PPCAnalyst::PrintCalls(addr);
}
else
{
LOG(CONSOLE, "Syntax: call ADDR");
}
}
CASE("llac")
{
TCHAR temp[256];
u32 addr;
sscanf(cmd, "%s %08x", temp, &addr);
if (addr!=0)
{
PPCAnalyst::PrintCallers(addr);
}
else
{
LOG(CONSOLE, "Syntax: llac ADDR");
}
}
CASE("pend")
{
CoreTiming::LogPendingEvents();
}
CASE("dump")
{
TCHAR temp[256];
TCHAR filename[256];
u32 start;
u32 end;
sscanf(cmd, "%s %08x %08x %s", temp, &start, &end, filename);
FILE *f = fopen(filename, "wb");
for (u32 i=start; i<end; i++)
{
u8 b = Memory::ReadUnchecked_U8(i);
fputc(b,f);
}
fclose(f);
LOG(CONSOLE, "Dumped from %08x to %08x to %s",start,end,filename);
}
CASE("disa")
{
u32 start;
u32 end;
TCHAR temp[256];
sscanf(cmd, "%s %08x %08x", temp, &start, &end);
for (u32 addr = start; addr <= end; addr += 4) {
u32 data = Memory::ReadUnchecked_U32(addr);
printf("%08x: %08x: %s\n", addr, data, DisassembleGekko(data, addr));
}
}
CASE("help")
{
LOG(CONSOLE, "Dolphin Console Command List");
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, "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, "lisd - list signature database");
LOG(CONSOLE, "lisf - list functions");
LOG(CONSOLE, "trans ADDR - translate address");
}
CASE("lisd")
{
PPCAnalyst::ListDB();
}
CASE("ipro")
{
PPCTables::PrintInstructionRunCounts();
}
CASE("lisf")
{
PPCAnalyst::ListFunctions();
}
else {
printf("blach\n");
LOG(CONSOLE, "Invalid command");
}
}

View File

@ -0,0 +1,24 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _CONSOLE_H
#define _CONSOLE_H
void Console_Submit(const char *cmd);
// void StartConsoleThread();
#endif

View File

@ -0,0 +1,496 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifdef _WIN32
#include <windows.h>
#else
#endif
#include "Thread.h"
#include "Timer.H"
#include "Console.h"
#include "Core.h"
#include "CoreTiming.h"
#include "Boot/Boot.h"
#include "PatchEngine.h"
#include "HW/Memmap.h"
#include "HW/PeripheralInterface.h"
#include "HW/GPFifo.h"
#include "HW/CPU.h"
#include "HW/CPUCompare.h"
#include "HW/HW.h"
#include "HW/DSP.h"
#include "HW/GPFifo.h"
#include "HW/AudioInterface.h"
#include "HW/VideoInterface.h"
#include "HW/CommandProcessor.h"
#include "HW/PixelEngine.h"
#include "HW/SystemTimers.h"
#include "PowerPC/PowerPC.h"
#include "Plugins/Plugin_Video.h"
#include "Plugins/Plugin_PAD.h"
#include "Plugins/Plugin_DSP.h"
#include "MemTools.h"
#include "Host.h"
#include "LogManager.h"
#ifndef _WIN32
#define WINAPI
#endif
// The idea behind the recent restructure is to fix various stupid problems.
// glXMakeCurrent/ wglMakeCurrent takes a context and makes it current on the current thread.
// So it's fine to init ogl on one thread, and then make it current and start blasting on another.
namespace Core
{
// forwarding
//void Callback_VideoRequestWindowSize(int _iWidth, int _iHeight, BOOL _bFullscreen);
void Callback_VideoLog(const TCHAR* _szMessage, BOOL _bDoBreak);
void Callback_VideoCopiedToXFB();
void Callback_DSPLog(const TCHAR* _szMessage);
void Callback_DSPInterrupt();
void Callback_DVDLog(const TCHAR* _szMessage);
void Callback_DVDSetStatusbar(TCHAR* _szMessage);
void Callback_PADLog(const TCHAR* _szMessage);
TPeekMessages Callback_PeekMessages = NULL;
TUpdateFPSDisplay g_pUpdateFPSDisplay = NULL;
#ifdef _WIN32
DWORD WINAPI EmuThread(void *pArg);
#else
void *EmuThread(void *pArg);
#endif
void Stop();
bool g_bHwInit = false;
HWND g_pWindowHandle = NULL;
Common::Thread* g_pThread = NULL;
SCoreStartupParameter g_CoreStartupParameter; //uck
Common::Event emuThreadGoing;
// Called from GUI thread
bool Init(const SCoreStartupParameter _CoreParameter)
{
if (g_pThread != NULL)
return false;
LogManager::Init();
Host_SetWaitCursor(true);
g_CoreStartupParameter = _CoreParameter;
// Init the Hardware
// start the thread again
_dbg_assert_(HLE, g_pThread == NULL);
// load plugins
if (!PluginDSP::LoadPlugin(g_CoreStartupParameter.m_strDSPPlugin.c_str())) {
PanicAlert("Failed to load DSP plugin %s", g_CoreStartupParameter.m_strDSPPlugin.c_str());
return false;
}
if (!PluginPAD::LoadPlugin(g_CoreStartupParameter.m_strPadPlugin.c_str())) {
PanicAlert("Failed to load PAD plugin %s", g_CoreStartupParameter.m_strPadPlugin.c_str());
return false;
}
if (!PluginVideo::LoadPlugin(g_CoreStartupParameter.m_strVideoPlugin.c_str())) {
PanicAlert("Failed to load video plugin %s", g_CoreStartupParameter.m_strVideoPlugin.c_str());
return false;
}
#ifdef _WIN32
PluginDSP::DllDebugger((HWND)_CoreParameter.hMainWindow);
#endif
emuThreadGoing.Init();
g_pThread = new Common::Thread(EmuThread, (void*)&g_CoreStartupParameter);
emuThreadGoing.Wait();
emuThreadGoing.Shutdown();
// all right ... here we go
Host_SetWaitCursor(false);
return true;
}
// Called from GUI thread or VI thread
void Stop() // - Hammertime!
{
Host_SetWaitCursor(true);
if (PowerPC::state == PowerPC::CPU_POWERDOWN)
return;
// stop the CPU
PowerPC::state = PowerPC::CPU_POWERDOWN;
CCPU::StepOpcode(); //kick it if it's waiting
// The quit is to get it out of its message loop
// Should be moved inside the plugin.
#ifdef _WIN32
PostMessage((HWND)g_pWindowHandle, WM_QUIT, 0, 0);
#else
// TODO(ector) : post message exit
#endif
delete g_pThread; //Wait for emuthread to close
Core::StopTrace();
LogManager::Shutdown();
g_pThread = 0;
Host_SetWaitCursor(false);
}
THREAD_RETURN CpuThread(void *pArg)
{
Common::SetCurrentThreadName("CPU thread");
const SCoreStartupParameter& _CoreParameter = g_CoreStartupParameter;
if (!g_CoreStartupParameter.bUseDualCore)
{
PluginVideo::Video_Prepare(); //wglMakeCurrent
}
if (_CoreParameter.bRunCompareServer)
{
CPUCompare::StartServer();
PowerPC::state = PowerPC::CPU_RUNNING;
}
else if (_CoreParameter.bRunCompareClient)
{
PanicAlert("Compare Debug : Press OK when ready.");
CPUCompare::ConnectAsClient();
}
Common::Thread::SetCurrentThreadAffinity(1); //Force to first core
// Let's run under memory watch
EMM::InstallExceptionHandler();
// StartConsoleThread();
CCPU::Run();
if (_CoreParameter.bRunCompareServer || _CoreParameter.bRunCompareClient)
{
CPUCompare::Stop();
}
return 0;
}
void Callback_DebuggerBreak()
{
CCPU::EnableStepping(true);
}
THREAD_RETURN EmuThread(void *pArg)
{
Host_BootingStarted();
Common::SetCurrentThreadName("Emuthread - starting");
const SCoreStartupParameter& _CoreParameter = *(SCoreStartupParameter*)pArg;
Common::Thread::SetCurrentThreadAffinity(2); //Force to second core
LOG(OSREPORT, "Starting core = %s mode", _CoreParameter.bWii ? "Wii" : "Gamecube");
LOG(OSREPORT, "Dualcore = %s", _CoreParameter.bUseDualCore ? "Yes" : "No");
HW::Init();
emuThreadGoing.Set();
// Load the VideoPlugin
SVideoInitialize VideoInitialize;
VideoInitialize.pGetMemoryPointer = Memory::GetPointer;
VideoInitialize.pSetPEToken = PixelEngine::SetToken;
VideoInitialize.pSetPEFinish = PixelEngine::SetFinish;
VideoInitialize.pWindowHandle = NULL; //_CoreParameter.hMainWindow; // NULL; // filled by video_initialize
VideoInitialize.pLog = Callback_VideoLog;
VideoInitialize.pRequestWindowSize = NULL; //Callback_VideoRequestWindowSize;
VideoInitialize.pCopiedToXFB = Callback_VideoCopiedToXFB;
VideoInitialize.pVIRegs = VideoInterface::m_UVIUnknownRegs;
VideoInitialize.pPeekMessages = NULL;
VideoInitialize.pUpdateFPSDisplay = NULL;
VideoInitialize.pCPFifo = (SCPFifoStruct*)&CommandProcessor::fifo;
VideoInitialize.pUpdateInterrupts = &(CommandProcessor::UpdateInterruptsFromVideoPlugin);
VideoInitialize.pMemoryBase = Memory::base;
PluginVideo::Video_Initialize(&VideoInitialize);
// Under linux, this is an X11 Display, not an HWND!
g_pWindowHandle = (HWND)VideoInitialize.pWindowHandle;
Callback_PeekMessages = VideoInitialize.pPeekMessages;
g_pUpdateFPSDisplay = VideoInitialize.pUpdateFPSDisplay;
// Load and init DSPPlugin
DSPInitialize dspInit;
dspInit.hWnd = g_pWindowHandle;
dspInit.pARAM_Read_U8 = (u8 (__cdecl *)(const u32))DSP::ReadARAM;
dspInit.pGetARAMPointer = DSP::GetARAMPtr;
dspInit.pGetMemoryPointer = Memory::GetPointer;
dspInit.pLog = Callback_DSPLog;
dspInit.pDebuggerBreak = Callback_DebuggerBreak;
dspInit.pGenerateDSPInterrupt = Callback_DSPInterrupt;
dspInit.pGetAudioStreaming = AudioInterface::Callback_GetStreaming;
PluginDSP::DSP_Initialize(dspInit);
// Load and Init PadPlugin
SPADInitialize PADInitialize;
PADInitialize.hWnd = g_pWindowHandle;
PADInitialize.pLog = Callback_PADLog;
PluginPAD::PAD_Initialize(PADInitialize);
// The hardware is initialized.
g_bHwInit = true;
// Load GCM/DOL/ELF whatever ... we boot with the interpreter core
PowerPC::SetCore(PowerPC::CORE_INTERPRETER);
CBoot::BootUp(_CoreParameter);
if( g_pUpdateFPSDisplay != NULL )
g_pUpdateFPSDisplay("Loading...");
// setup our core, but can't use dynarec if we are compare server
if (_CoreParameter.bUseDynarec && !_CoreParameter.bRunCompareServer || _CoreParameter.bRunCompareClient)
PowerPC::SetCore(PowerPC::CORE_DYNAREC);
else
PowerPC::SetCore(PowerPC::CORE_INTERPRETER);
// update the window again because all stuff is initialized
Host_UpdateDisasmDialog();
Host_UpdateMainFrame();
Host_BootingEnded();
//This thread, after creating the EmuWindow, spawns a CPU thread,
//then takes over and becomes the graphics thread
//In single core mode, the CPU thread does the graphics. In fact, the
//CPU thread should in this case also create the emuwindow...
//Spawn the CPU thread
Common::Thread *cpuThread = new Common::Thread(CpuThread, pArg);
//////////////////////////////////////////////////////////////////////////
// ENTER THE VIDEO THREAD LOOP
//////////////////////////////////////////////////////////////////////////
if (!Core::GetStartupParameter().bUseDualCore)
{
Common::SetCurrentThreadName("Idle thread");
//TODO(ector) : investigate using GetMessage instead .. although
//then we lose the powerdown check. ... unless powerdown sends a message :P
while (PowerPC::state != PowerPC::CPU_POWERDOWN)
{
if (Callback_PeekMessages) {
Callback_PeekMessages();
}
Common::SleepCurrentThread(20);
}
}
else
{
PluginVideo::Video_Prepare(); //wglMakeCurrent
Common::SetCurrentThreadName("Video thread");
PluginVideo::Video_EnterLoop();
}
// Wait for CPU thread to exit - it should have been signaled to do so by now
if( g_pUpdateFPSDisplay != NULL )
g_pUpdateFPSDisplay("Stopping...");
delete cpuThread;
// Returns after game exited
g_bHwInit = false;
PluginPAD::PAD_Shutdown();
PluginPAD::UnloadPlugin();
PluginDSP::DSP_Shutdown();
PluginDSP::UnloadPlugin();
PluginVideo::Video_Shutdown();
PluginVideo::UnloadPlugin();
HW::Shutdown();
LOG(MASTER_LOG,"EmuThread exited");
//The CPU should return when a game is stopped and cleanup should be done here,
//so we can restart the plugins (or load new ones) for the next game
Host_UpdateMainFrame();
return 0;
}
bool SetState(EState _State)
{
switch(_State)
{
case CORE_UNINITIALIZED:
Stop();
break;
case CORE_PAUSE:
CCPU::EnableStepping(true);
break;
case CORE_RUN:
CCPU::EnableStepping(false);
break;
default:
return false;
}
return true;
}
EState GetState()
{
if (g_bHwInit)
{
if (CCPU::IsStepping())
return CORE_PAUSE;
else
return CORE_RUN;
}
return CORE_UNINITIALIZED;
}
const SCoreStartupParameter& GetStartupParameter()
{
return g_CoreStartupParameter;
}
bool MakeScreenshot(const std::string& _rFilename)
{
bool bResult = false;
if (PluginVideo::IsLoaded())
{
TCHAR szTmpFilename[MAX_PATH];
strcpy(szTmpFilename, _rFilename.c_str());
bResult = PluginVideo::Video_Screenshot(szTmpFilename);
}
return bResult;
}
void* GetWindowHandle()
{
return g_pWindowHandle;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// --- Callbacks for plugins / engine ---
/////////////////////////////////////////////////////////////////////////////////////////////////////
// __________________________________________________________________________________________________
// Callback_VideoLog
// WARNING - THIS IS EXECUTED FROM VIDEO THREAD
void Callback_VideoLog(const TCHAR *_szMessage, BOOL _bDoBreak)
{
LOG(VIDEO, _szMessage);
}
// __________________________________________________________________________________________________
// Callback_VideoCopiedToXFB
// WARNING - THIS IS EXECUTED FROM VIDEO THREAD
// We do not touch anything outside this function here
void Callback_VideoCopiedToXFB()
{
//count FPS
static Common::Timer Timer;
static u32 frames = 0;
static u64 ticks = 0;
static u64 idleTicks = 0;
frames++;
if (Timer.GetTimeDifference() >= 1000)
{
u64 newTicks = CoreTiming::GetTicks();
u64 newIdleTicks = CoreTiming::GetIdleTicks();
s64 diff = (newTicks - ticks)/1000000;
s64 idleDiff = (newIdleTicks - idleTicks)/1000000;
ticks = newTicks;
idleTicks = newIdleTicks;
float t = (float)(Timer.GetTimeDifference()) / 1000.f;
char isoName[64];
isoName[0] = 0x00;
char temp[256];
sprintf(temp, "%s - FPS: %8.2f - %s - %i MHz (%i real, %i idle skipped) out of %i MHz",
isoName, (float)frames / t,
g_CoreStartupParameter.bUseDynarec ? "JIT" : "Interpreter",
(int)(diff),
(int)(diff-idleDiff),
(int)(idleDiff),
SystemTimers::GetTicksPerSecond()/1000000);
if( g_pUpdateFPSDisplay != NULL )
g_pUpdateFPSDisplay(temp);
frames = 0;
Timer.Update();
}
PatchEngine_ApplyFramePatches();
}
// __________________________________________________________________________________________________
// Callback_DSPLog
// WARNING - THIS MAY EXECUTED FROM DSP THREAD
void Callback_DSPLog(const TCHAR* _szMessage)
{
LOG(AUDIO, _szMessage);
}
// __________________________________________________________________________________________________
// Callback_DSPInterrupt
// WARNING - THIS MAY EXECUTED FROM DSP THREAD
void Callback_DSPInterrupt()
{
DSP::GenerateDSPInterruptFromPlugin(DSP::INT_DSP);
}
// __________________________________________________________________________________________________
// Callback_DVDLog
//
void Callback_DVDLog(TCHAR* _szMessage)
{
LOG(DVDINTERFACE, _szMessage);
}
// __________________________________________________________________________________________________
// Callback_DVDSetStatusbar
//
void Callback_DVDSetStatusbar(TCHAR* _szMessage)
{
//Todo: PostMessage to main window to set the string
// strDVDMessage = _szMessage;
// if (g_CoreStartupParameter.m_StatusUpdate != NULL)
// g_CoreStartupParameter.m_StatusUpdate();
}
// __________________________________________________________________________________________________
// Callback_PADLog
//
void Callback_PADLog(const TCHAR* _szMessage)
{
LOG(SERIALINTERFACE, _szMessage);
}
} // end of namespace Core

View File

@ -0,0 +1,65 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _CORE_H
#define _CORE_H
#include <vector>
#include <string>
#include "Common.h"
#include "CoreParameter.h"
namespace Core
{
enum EState
{
CORE_UNINITIALIZED,
CORE_PAUSE,
CORE_RUN,
};
// Init core
bool Init(const SCoreStartupParameter _CoreParameter);
void Stop();
// Get state
bool SetState(EState _State);
// Get state
EState GetState();
// get core parameters
extern SCoreStartupParameter g_CoreStartupParameter; //uck
const SCoreStartupParameter& GetStartupParameter();
// make a screen shot
bool MakeScreenshot(const std::string& _rFilename);
void* GetWindowHandle();
extern bool bReadTrace;
extern bool bWriteTrace;
void StartTrace(bool write);
int SyncTrace();
void SetBlockStart(u32 addr);
void StopTrace();
} // end of namespace Core
#endif

View File

@ -0,0 +1,144 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "Boot/Boot.h"
#include "StringUtil.h"
#include "CoreParameter.h"
#include "VolumeCreator.h"
SCoreStartupParameter::SCoreStartupParameter()
{
LoadDefaults();
}
void SCoreStartupParameter::LoadDefaults()
{
bEnableDebugging = false;
bUseDynarec = false;
bUseDualCore = false;
bRunCompareServer = false;
bWii = false;
}
bool SCoreStartupParameter::AutoSetup(EBootBios _BootBios)
{
static const char *s_DataBasePath_EUR = "Data_EUR";
static const char *s_DataBasePath_USA = "Data_USA";
static const char *s_DataBasePath_JAP = "Data_JAP";
std::string BaseDataPath(s_DataBasePath_EUR);
switch (_BootBios)
{
case BOOT_DEFAULT:
{
std::string Extension;
SplitPath(m_strFilename, NULL, NULL, &Extension);
if (!stricmp(Extension.c_str(), ".gcm") ||
!stricmp(Extension.c_str(), ".iso") ||
!stricmp(Extension.c_str(), ".gcz") )
{
m_BootType = BOOT_ISO;
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(m_strFilename.c_str());
if (pVolume == NULL)
{
PanicAlert("Your GCM/ISO file seems to be invalid, or not a GC/Wii ISO.");
return false;
}
bWii = DiscIO::IsVolumeWiiDisc(*pVolume);
switch (pVolume->GetCountry())
{
case DiscIO::IVolume::COUNTRY_USA:
bNTSC = true;
BaseDataPath = s_DataBasePath_USA;
break;
case DiscIO::IVolume::COUNTRY_JAP:
bNTSC = true;
BaseDataPath = s_DataBasePath_JAP;
break;
case DiscIO::IVolume::COUNTRY_EUROPE:
case DiscIO::IVolume::COUNTRY_FRANCE:
bNTSC = false;
BaseDataPath = s_DataBasePath_EUR;
break;
default:
PanicAlert("Your GCM/ISO file seems to be invalid (invalid country).");
return false;
}
delete pVolume;
}
else if (!stricmp(Extension.c_str(), ".elf"))
{
bWii = CBoot::IsElfWii(m_strFilename.c_str());
BaseDataPath = s_DataBasePath_USA;
m_BootType = BOOT_ELF;
bNTSC = true;
}
else if (!stricmp(Extension.c_str(), ".bin"))
{
BaseDataPath = s_DataBasePath_USA;
m_BootType = BOOT_BIN;
bNTSC = true;
}
else if (!stricmp(Extension.c_str(), ".dol"))
{
BaseDataPath = s_DataBasePath_USA;
m_BootType = BOOT_DOL;
bNTSC = true;
}
else
{
PanicAlert("Could not recognize ISO file %s", m_strFilename.c_str());
return false;
}
}
break;
case BOOT_BIOS_USA:
BaseDataPath = s_DataBasePath_USA;
m_strFilename.clear();
bNTSC = true;
break;
case BOOT_BIOS_JAP:
BaseDataPath = s_DataBasePath_JAP;
m_strFilename.clear();
bNTSC = true;
break;
case BOOT_BIOS_EUR:
BaseDataPath = s_DataBasePath_EUR;
m_strFilename.clear();
bNTSC = false;
break;
}
// setup paths
m_strBios = BaseDataPath + "/IPL.bin";
m_strMemoryCardA = BaseDataPath + "/MemoryCardA.raw";
m_strMemoryCardB = BaseDataPath + "/MemoryCardB.raw";
m_strSRAM = BaseDataPath + "/SRAM.raw";
}

View File

@ -0,0 +1,89 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _COREPARAMETER_H
#define _COREPARAMETER_H
#ifdef _WIN32
#include <windows.h>
#endif
#include <string>
struct SCoreStartupParameter
{
#ifdef _WIN32
HINSTANCE hInstance;
#endif
// windows/GUI related
void* hMainWindow;
// flags
bool bEnableDebugging;
bool bUseDynarec;
bool bUseDualCore;
bool bNTSC;
bool bHLEBios;
bool bThrottle;
bool bUseFastMem;
bool bRunCompareServer;
bool bRunCompareClient;
bool bWii;
enum EBootBios
{
BOOT_DEFAULT,
BOOT_BIOS_JAP,
BOOT_BIOS_USA,
BOOT_BIOS_EUR,
};
enum EBootType
{
BOOT_ISO,
BOOT_ELF,
BOOT_BIN,
BOOT_DOL,
BOOT_BIOS
};
EBootType m_BootType;
// files
std::string m_strVideoPlugin;
std::string m_strPadPlugin;
std::string m_strDSPPlugin;
std::string m_strFilename;
std::string m_strBios;
std::string m_strMemoryCardA;
std::string m_strMemoryCardB;
std::string m_strSRAM;
std::string m_strDefaultGCM;
//
SCoreStartupParameter();
void LoadDefaults();
bool AutoSetup(EBootBios _BootBios);
};
#endif

View File

@ -0,0 +1,270 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Thread.h"
#include "PowerPC/PowerPC.h"
#include "CoreTiming.h"
// TODO(ector): Replace new/delete in this file with a simple memory pool
// Don't expect a massive speedup though.
namespace CoreTiming
{
int downcount, slicelength;
int maxSliceLength = 20000;
s64 globalTimer;
s64 idledCycles;
u64 GetTicks()
{
return (u64)globalTimer;
}
u64 GetIdleTicks()
{
return (u64)idledCycles;
}
struct Event
{
TimedCallback callback;
Event *next;
s64 time;
u64 userdata;
const char *name;
};
Event *first;
Event *tsFirst;
Common::CriticalSection externalEventSection;
// This is to be called when outside threads, such as the graphics thread, wants to
// schedule things to be executed on the main thread.
void ScheduleEvent_Threadsafe(int cyclesIntoFuture, TimedCallback callback, const char *name, u64 userdata)
{
externalEventSection.Enter();
Event *ne = new Event;
ne->time = globalTimer + cyclesIntoFuture;
ne->name = name;
ne->callback = callback;
ne->next = tsFirst;
ne->userdata = userdata;
tsFirst = ne;
externalEventSection.Leave();
}
void Clear()
{
globalTimer = 0;
idledCycles = 0;
while (first)
{
Event *e = first->next;
delete [] first;
first = e;
}
}
void AddEventToQueue(Event *ne)
{
// Damn, this logic got complicated. Must be an easier way.
if (!first)
{
first = ne;
ne->next = 0;
}
else
{
Event *ptr = first;
Event *prev = 0;
if (ptr->time > ne->time)
{
ne->next = first;
first = ne;
}
else
{
prev = first;
ptr = first->next;
while (ptr)
{
if (ptr->time <= ne->time)
{
prev = ptr;
ptr = ptr->next;
}
else
break;
}
//OK, ptr points to the item AFTER our new item. Let's insert
ne->next = prev->next;
prev->next = ne;
// Done!
}
}
}
// This must be run ONLY from within the cpu thread
// cyclesIntoFuture may be VERY inaccurate if called from anything else
// than Advance
void ScheduleEvent(int cyclesIntoFuture, TimedCallback callback, const char *name, u64 userdata)
{
Event *ne = new Event;
ne->callback = callback;
ne->userdata = userdata;
ne->name = name;
ne->time = globalTimer + cyclesIntoFuture;
AddEventToQueue(ne);
}
void (*advanceCallback)(int cyclesExecuted);
void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted))
{
advanceCallback = callback;
}
bool IsScheduled(TimedCallback callback)
{
if (!first)
return false;
Event *e = first;
while (e) {
if (e->callback == callback)
return true;
e = e->next;
}
return false;
}
void RemoveEvent(TimedCallback callback)
{
if (!first)
return;
if (first->callback == callback)
{
Event *next = first->next;
delete first;
first = next;
}
if (!first)
return;
Event *prev = first;
Event *ptr = prev->next;
while (ptr)
{
if (ptr->callback == callback)
{
prev->next = ptr->next;
delete ptr;
ptr = prev->next;
}
else
{
prev = ptr;
ptr = ptr->next;
}
}
}
void SetMaximumSlice(int maximumSliceLength)
{
maxSliceLength = maximumSliceLength;
}
void Advance()
{
// Move events from async queue into main queue
externalEventSection.Enter();
while (tsFirst)
{
//MessageBox(0,"yay",0,0);
Event *next = tsFirst->next;
AddEventToQueue(tsFirst);
tsFirst = next;
}
externalEventSection.Leave();
// we are out of run, downcount = -3
int cyclesExecuted = slicelength - downcount;
// sliceLength = downac
globalTimer += cyclesExecuted;
while (first)
{
if (first->time <= globalTimer)
{
// LOG(GEKKO, "[Scheduler] %s (%lld, %lld) ",
// first->name ? first->name : "?", (u64)globalTimer, (u64)first->time);
first->callback(first->userdata, (int)(globalTimer - first->time));
Event *next = first->next;
delete first;
first = next;
}
else
{
break;
}
}
if (!first)
{
LOG(GEKKO, "WARNING - no events in queue. Setting downcount to 10000");
downcount += 10000;
}
else
{
slicelength = (int)(first->time - globalTimer);
if (slicelength > maxSliceLength)
slicelength = maxSliceLength;
downcount = slicelength;
}
if (advanceCallback)
advanceCallback(cyclesExecuted);
}
void LogPendingEvents()
{
Event *ptr = first;
while (ptr)
{
LOG(GEKKO, "PENDING: Now: %lld Pending: %lld %s", globalTimer, ptr->time, ptr->name);
ptr = ptr->next;
}
}
void Idle()
{
LOG(GEKKO, "Idle");
idledCycles += downcount;
downcount = 0;
Advance();
}
}; // end of namespace

View File

@ -0,0 +1,54 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _CORETIMING_H
#define _CORETIMING_H
#include "Common.h"
namespace CoreTiming
{
enum {
SOON = 100
};
typedef void (*TimedCallback)(u64 userdata, int cyclesLate);
u64 GetTicks();
u64 GetIdleTicks();
// The int that the callbacks get is how many cycles late it was.
// So to schedule a new event on a regular basis:
// inside callback:
// ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
void ScheduleEvent(int cyclesIntoFuture, TimedCallback callback, const char *name, u64 userdata=0);
void ScheduleEvent_Threadsafe(int cyclesIntoFuture, TimedCallback callback, const char *name, u64 userdata=0);
void RemoveEvent(TimedCallback callback);
bool IsScheduled(TimedCallback callback);
void Advance();
void Idle();
void Clear();
void LogPendingEvents();
void SetMaximumSlice(int maximumSliceLength);
void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted));
extern int downcount;
extern int slicelength;
}; // end of namespace
#endif

View File

@ -0,0 +1,27 @@
#ifndef _DEBUGINTERFACE_H
#define _DEBUGINTERFACE_H
#include <string>
class DebugInterface
{
public:
virtual const char *disasm(unsigned int /*address*/) {return "NODEBUGGER";}
virtual int getInstructionSize(int /*instruction*/) {return 1;}
virtual bool isAlive() {return true;}
virtual bool isBreakpoint(unsigned int /*address*/) {return false;}
virtual void setBreakpoint(unsigned int /*address*/){}
virtual void clearBreakpoint(unsigned int /*address*/){}
virtual void clearAllBreakpoints() {}
virtual void toggleBreakpoint(unsigned int /*address*/){}
virtual unsigned int readMemory(unsigned int /*address*/){return 0;}
virtual unsigned int getPC() {return 0;}
virtual void setPC(unsigned int /*address*/) {}
virtual void step() {}
virtual void runToBreakpoint() {}
virtual int getColor(unsigned int /*address*/){return 0xFFFFFFFF;}
virtual std::string getDescription(unsigned int /*address*/) = 0;
};
#endif

View File

@ -0,0 +1,147 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Lame slow breakpoint system
// TODO: a real one
#include "Common.h"
#include "../HW/CPU.h"
#include "Debugger_SymbolMap.h"
#include "Debugger_BreakPoints.h"
using namespace Debugger;
std::vector<TBreakPoint> CBreakPoints::m_iBreakPoints;
std::vector<TMemCheck> CBreakPoints::MemChecks;
u32 CBreakPoints::m_iBreakOnCount = 0;
TMemCheck::TMemCheck()
{
numHits = 0;
}
void TMemCheck::Action(u32 iValue, u32 addr, bool write, int size, u32 pc)
{
if ((write && bOnWrite) || (!write && bOnRead))
{
if (bLog)
{
const char *copy = Debugger::GetDescription(addr);
LOG(MEMMAP,"CHK %08x %s%i at %08x (%s)", iValue, write ? "Write" : "Read", size*8, addr, copy);
}
if (bBreak)
CCPU::Break();
}
}
bool CBreakPoints::IsAddressBreakPoint(u32 _iAddress)
{
std::vector<TBreakPoint>::iterator iter;
for (iter = m_iBreakPoints.begin(); iter != m_iBreakPoints.end(); ++iter)
if ((*iter).iAddress == _iAddress)
return true;
return false;
}
bool CBreakPoints::IsTempBreakPoint(u32 _iAddress)
{
std::vector<TBreakPoint>::iterator iter;
for (iter = m_iBreakPoints.begin(); iter != m_iBreakPoints.end(); ++iter)
if ((*iter).iAddress == _iAddress && (*iter).bTemporary)
return true;
return false;
}
TMemCheck *CBreakPoints::GetMemCheck(u32 address)
{
std::vector<TMemCheck>::iterator iter;
for (iter = MemChecks.begin(); iter != MemChecks.end(); ++iter)
{
if ((*iter).bRange)
{
if (address >= (*iter).iStartAddress && address <= (*iter).iEndAddress)
return &(*iter);
}
else
{
if ((*iter).iStartAddress==address)
return &(*iter);
}
}
//none found
return 0;
}
void CBreakPoints::AddBreakPoint(u32 _iAddress, bool temp)
{
if (!IsAddressBreakPoint(_iAddress))
{
TBreakPoint pt;
pt.bOn = true;
pt.bTemporary = temp;
pt.iAddress = _iAddress;
m_iBreakPoints.push_back(pt);
}
}
void CBreakPoints::RemoveBreakPoint(u32 _iAddress)
{
std::vector<TBreakPoint>::iterator iter;
for (iter = m_iBreakPoints.begin(); iter != m_iBreakPoints.end(); ++iter)
{
if ((*iter).iAddress == _iAddress)
{
m_iBreakPoints.erase(iter);
break;
}
}
}
void CBreakPoints::ClearAllBreakPoints()
{
m_iBreakPoints.clear();
}
void CBreakPoints::AddAutoBreakpoints()
{
#if defined(_DEBUG) || defined(DEBUGFAST)
#if 1
const char *bps[] = {
"PPCHalt",
};
for (int i = 0; i < sizeof(bps) / sizeof(const char *); i++)
{
XSymbolIndex idx = FindSymbol(bps[i]);
if (idx != 0)
{
const CSymbol &symbol = GetSymbol(idx);
AddBreakPoint(symbol.vaddress, false);
}
}
#endif
#endif
}

View File

@ -0,0 +1,89 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DEBUGGER_BREAKPOINTS_H
#define _DEBUGGER_BREAKPOINTS_H
#include <vector>
#include <string>
#include "Common.h"
struct TBreakPoint
{
u32 iAddress;
bool bOn;
bool bTemporary;
};
struct TMemCheck
{
TMemCheck();
u32 iStartAddress;
u32 iEndAddress;
bool bRange;
bool bOnRead;
bool bOnWrite;
bool bLog;
bool bBreak;
u32 numHits;
void Action(u32 _iValue, u32 addr, bool write, int size, u32 pc);
};
class CBreakPoints
{
private:
enum { MAX_NUMBER_OF_CALLSTACK_ENTRIES = 16384};
enum { MAX_NUMBER_OF_BREAKPOINTS = 16};
static std::vector<TBreakPoint> m_iBreakPoints;
static u32 m_iBreakOnCount;
public:
static std::vector<TMemCheck> MemChecks;
// is address breakpoint
static bool IsAddressBreakPoint(u32 _iAddress);
//memory breakpoint
static TMemCheck *GetMemCheck(u32 address);
// is break on count
static void SetBreakCount(u32 count) { m_iBreakOnCount = count; }
static u32 GetBreakCount() { return m_iBreakOnCount; }
static bool IsTempBreakPoint(u32 _iAddress);
// AddBreakPoint
static void AddBreakPoint(u32 _iAddress, bool temp=false);
// Remove Breakpoint
static void RemoveBreakPoint(u32 _iAddress);
static void ClearAllBreakPoints();
static void AddAutoBreakpoints();
};
#endif

View File

@ -0,0 +1,433 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "StringUtil.h"
#include "Debugger_SymbolMap.h"
#include "../HW/Memmap.h"
#include "../PowerPC/PowerPC.h"
#include "../PowerPC/PPCAnalyst.h"
#include "../../../../Externals/Bochs_disasm/PowerPCDisasm.h"
namespace Debugger
{
XVectorSymbol m_VectorSymbols;
CSymbol::CSymbol(u32 _Address, u32 _Size, ESymbolType _Type, const char *_rName) :
vaddress(_Address),
size(_Size),
runCount(0),
type(_Type),
m_strName(_rName)
{
// invalid entry
if (m_strName.size() < 2)
{
_Address = -1;
_Size = 0;
}
}
CSymbol::~CSymbol()
{
m_vecBackwardLinks.clear();
}
void Reset()
{
m_VectorSymbols.clear();
// 0 is an invalid entry
CSymbol Invalid(-1, 0, ST_FUNCTION, "Invalid");
m_VectorSymbols.push_back(Invalid);
}
XSymbolIndex AddSymbol(const CSymbol& _rSymbolMapEntry)
{
XSymbolIndex old = 0;
if ((old = FindSymbol(_rSymbolMapEntry.GetName().c_str())) != 0)
return old;
m_VectorSymbols.push_back(_rSymbolMapEntry);
return (XSymbolIndex)(m_VectorSymbols.size()-1);
}
const CSymbol& GetSymbol(XSymbolIndex _Index)
{
if (_Index < (XSymbolIndex)m_VectorSymbols.size())
return m_VectorSymbols[_Index];
PanicAlert("GetSymbol is called with an invalid index %i", _Index);
return m_VectorSymbols[0];
}
const XVectorSymbol& AccessSymbols()
{
return m_VectorSymbols;
}
CSymbol& AccessSymbol(XSymbolIndex _Index)
{
if (_Index < (XSymbolIndex)m_VectorSymbols.size())
return m_VectorSymbols[_Index];
PanicAlert("AccessSymbol is called with an invalid index %i", _Index);
return m_VectorSymbols[0];
}
XSymbolIndex FindSymbol(u32 _Address)
{
for (int i = 0; i < (int)m_VectorSymbols.size(); i++)
{
const CSymbol& rSymbol = m_VectorSymbols[i];
if ((_Address >= rSymbol.vaddress) && (_Address < rSymbol.vaddress + rSymbol.size))
{
return (XSymbolIndex)i;
}
}
// invalid index
return 0;
}
XSymbolIndex FindSymbol(const char *name)
{
for (int i = 0; i < (int)m_VectorSymbols.size(); i++)
{
const CSymbol& rSymbol = m_VectorSymbols[i];
if (stricmp(rSymbol.GetName().c_str(), name) == 0)
{
return (XSymbolIndex)i;
}
}
// invalid index
return 0;
}
// __________________________________________________________________________________________________
// LoadSymbolMap
//
bool LoadSymbolMap(const char *_szFilename)
{
Reset();
FILE *f = fopen(_szFilename, "r");
if (!f)
return false;
//char temp[256];
//fgets(temp,255,f); //.text section layout
//fgets(temp,255,f); // Starting Virtual
//fgets(temp,255,f); // address Size address
//fgets(temp,255,f); // -----------------------
bool started=false;
while (!feof(f))
{
char line[512],temp[256];
fgets(line,511,f);
if (strlen(line)<4)
continue;
sscanf(line,"%s",temp);
if (strcmp(temp,"UNUSED")==0) continue;
if (strcmp(temp,".text")==0) {started = true; continue;};
if (strcmp(temp,".init")==0) {started = true; continue;};
if (strcmp(temp,"Starting")==0) continue;
if (strcmp(temp,"extab")==0) continue;
if (strcmp(temp,".ctors")==0) break; //uh?
if (strcmp(temp,".dtors")==0) break;
if (strcmp(temp,".rodata")==0) continue;
if (strcmp(temp,".data")==0) continue;
if (strcmp(temp,".sbss")==0) continue;
if (strcmp(temp,".sdata")==0) continue;
if (strcmp(temp,".sdata2")==0) continue;
if (strcmp(temp,"address")==0) continue;
if (strcmp(temp,"-----------------------")==0) continue;
if (strcmp(temp,".sbss2")==0) break;
if (temp[1]==']') continue;
if (!started) continue;
// read out the entry
u32 address, vaddress, size, unknown;
char name[512];
sscanf(line,"%08x %08x %08x %i %s",&address, &size, &vaddress, &unknown, name);
char *namepos = strstr(line, name);
if (namepos != 0) //would be odd if not :P
strcpy(name, namepos);
name[strlen(name)-1] = 0;
// we want the function names only ....
for (size_t i=0; i<strlen(name); i++)
{
if (name[i] == ' ') name[i] = 0x00;
if (name[i] == '(') name[i] = 0x00;
}
// check if this is a valid entry
if (strcmp(name,".text")!=0 ||
strcmp(name,".init")!=0 ||
strlen(name) > 0)
{
AddSymbol(CSymbol(vaddress | 0x80000000, size, ST_FUNCTION, name));
}
}
fclose(f);
// AnalyzeBackwards();
return true;
}
// __________________________________________________________________________________________________
// SaveSymbolMap
//
void SaveSymbolMap(const char *_rFilename)
{
FILE *f = fopen(_rFilename,"w");
if (!f)
return;
fprintf(f,".text\n");
XVectorSymbol::const_iterator itr = m_VectorSymbols.begin();
while(itr != m_VectorSymbols.end())
{
const CSymbol& rSymbol = *itr;
fprintf(f,"%08x %08x %08x %i %s\n",rSymbol.vaddress,rSymbol.size,rSymbol.vaddress,0,rSymbol.GetName().c_str());
itr++;
}
fclose(f);
}
// =========================================================================================================
void MergeMapWithDB(const char *beginning)
{
XVectorSymbol::const_iterator itr = m_VectorSymbols.begin();
while(itr != m_VectorSymbols.end())
{
const CSymbol& rSymbol = *itr;
if (rSymbol.type == ST_FUNCTION && rSymbol.size>=12)
{
// if (!beginning || !strlen(beginning) || !(memcmp(beginning,rSymbol.name,strlen(beginning))))
PPCAnalyst::AddToFuncDB(rSymbol.vaddress, rSymbol.size, rSymbol.GetName().c_str());
}
itr++;
}
PPCAnalyst::UseFuncDB();
PPCAnalyst::SaveFuncDB("e:\\test.db");
// PanicAlert("MergeMapWiintthDB : %s", beginning);
}
void GetFromAnalyzer()
{
struct local {static void AddSymb(PPCAnalyst::SFunction *f)
{
Debugger::AddSymbol(CSymbol(f->address, f->size*4, ST_FUNCTION, f->name.c_str()));
}};
PPCAnalyst::GetAllFuncs(local::AddSymb);
}
const char *GetDescription(u32 _Address)
{
Debugger::XSymbolIndex Index = Debugger::FindSymbol(_Address);
if (Index > 0)
return GetSymbol(Index).GetName().c_str();
else
return "(unk.)";
}
//
// --- shouldn't be here ---
//
#ifdef _WIN32
void FillSymbolListBox(HWND listbox, ESymbolType symmask)
{
ShowWindow(listbox,SW_HIDE);
ListBox_ResetContent(listbox);
int style = GetWindowLong(listbox,GWL_STYLE);
ListBox_SetItemData(listbox,ListBox_AddString(listbox,"_(0x80000000)"),0x80000000);
ListBox_SetItemData(listbox,ListBox_AddString(listbox,"_(0x81FFFFFF)"),0x81FFFFFF);
ListBox_SetItemData(listbox,ListBox_AddString(listbox,"_(0x80003100)"),0x80003100);
ListBox_SetItemData(listbox,ListBox_AddString(listbox,"_(0x90000000)"),0x90000000);
ListBox_SetItemData(listbox,ListBox_AddString(listbox,"_(0x93FFFFFF)"),0x93FFFFFF);
XVectorSymbol::const_iterator itr = m_VectorSymbols.begin();
while (itr != m_VectorSymbols.end())
{
const CSymbol& rSymbol = *itr;
if (rSymbol.type & symmask)
{
int index = ListBox_AddString(listbox,rSymbol.GetName().c_str());
ListBox_SetItemData(listbox,index,rSymbol.vaddress);
}
itr++;
}
ShowWindow(listbox,SW_SHOW);
}
void FillListBoxBLinks(HWND listbox, XSymbolIndex _Index)
{
/* ListBox_ResetContent(listbox);
int style = GetWindowLong(listbox,GWL_STYLE);
CSymbol &e = entries[num];*/
#ifdef BWLINKS
for (int i=0; i<e.backwardLinks.size(); i++)
{
u32 addr = e.backwardLinks[i];
int index = ListBox_AddString(listbox,GetSymbolName(GetSymbolNum(addr)));
ListBox_SetItemData(listbox,index,addr);
}
#endif
}
#endif
void AnalyzeBackwards()
{
#ifndef BWLINKS
return;
#else
for (int i=0; i<numEntries; i++)
{
u32 ptr = entries[i].vaddress;
if (ptr && entries[i].type == ST_FUNCTION)
{
for (int a = 0; a<entries[i].size/4; a++)
{
u32 inst = Memory::ReadUnchecked_U32(ptr);
switch (inst>>26)
{
case 18:
if (LK) //LK
{
u32 addr;
if(AA)
addr = SignExt26(LI << 2);
else
addr = ptr + SignExt26(LI << 2);
int funNum = GetSymbolNum(addr);
if (funNum>=0)
entries[funNum].backwardLinks.push_back(ptr);
}
break;
default:
;
}
ptr+=4;
}
}
}
#endif
}
bool GetCallstack(std::vector<SCallstackEntry> &output)
{
if (!Memory::IsRAMAddress(PowerPC::ppcState.gpr[1]))
return false;
u32 addr = Memory::ReadUnchecked_U32(PowerPC::ppcState.gpr[1]); // SP
if (LR == 0) {
SCallstackEntry entry;
entry.Name = "(error: LR=0)";
entry.vAddress = 0x0;
output.push_back(entry);
return false;
}
int count = 1;
if (GetDescription(PowerPC::ppcState.pc) != GetDescription(LR))
{
SCallstackEntry entry;
entry.Name = StringFromFormat(" * %s [ LR = %08x ]\n", Debugger::GetDescription(LR), LR);
entry.vAddress = 0x0;
count++;
}
//walk the stack chain
while ((addr != 0xFFFFFFFF) && (addr != 0) && (count++ < 20) && (PowerPC::ppcState.gpr[1] != 0))
{
if (!Memory::IsRAMAddress(addr + 4))
return false;
u32 func = Memory::ReadUnchecked_U32(addr + 4);
const char *str = Debugger::GetDescription(func);
if (!str || strlen(str) == 0 || !strcmp(str, "Invalid"))
str = "(unknown)";
SCallstackEntry entry;
entry.Name = StringFromFormat(" * %s [ addr = %08x ]\n", str, func);
entry.vAddress = func;
output.push_back(entry);
if (!Memory::IsRAMAddress(addr))
return false;
addr = Memory::ReadUnchecked_U32(addr);
}
return true;
}
void PrintCallstack() {
u32 addr = Memory::ReadUnchecked_U32(PowerPC::ppcState.gpr[1]); // SP
printf("\n == STACK TRACE - SP = %08x ==\n", PowerPC::ppcState.gpr[1]);
if (LR == 0) {
printf(" LR = 0 - this is bad\n");
}
int count = 1;
if (GetDescription(PowerPC::ppcState.pc) != GetDescription(LR))
{
printf(" * %s [ LR = %08x ]\n", Debugger::GetDescription(LR), LR);
count++;
}
//walk the stack chain
while ((addr != 0xFFFFFFFF) && (addr != 0) && (count++ < 20) && (PowerPC::ppcState.gpr[1] != 0))
{
u32 func = Memory::ReadUnchecked_U32(addr + 4);
const char *str = Debugger::GetDescription(func);
if (!str || strlen(str) == 0 || !strcmp(str, "Invalid"))
str = "(unknown)";
printf( " * %s [ addr = %08x ]\n", str, func);
addr = Memory::ReadUnchecked_U32(addr);
}
}
} // end of namespace Debugger

View File

@ -0,0 +1,102 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DEBUGGER_SYMBOLMAP_H
#define _DEBUGGER_SYMBOLMAP_H
#include <vector>
#include <string>
#include "Common.h"
namespace Debugger
{
enum ESymbolType
{
ST_FUNCTION = 1,
ST_DATA = 2
};
class CSymbol
{
public:
u32 vaddress;
u32 size;
u32 runCount;
ESymbolType type;
CSymbol(u32 _Address, u32 _Size, ESymbolType _Type, const char *_rName);
~CSymbol();
const std::string &GetName() const { return m_strName; }
void SetName(const char *_rName) { m_strName = _rName; }
private:
std::string m_strName;
std::vector <u32> m_vecBackwardLinks;
};
typedef int XSymbolIndex;
typedef std::vector<CSymbol> XVectorSymbol;
void Reset();
XSymbolIndex AddSymbol(const CSymbol& _rSymbolMapEntry);
const CSymbol& GetSymbol(XSymbolIndex _Index);
CSymbol& AccessSymbol(XSymbolIndex _Index);
const XVectorSymbol& AccessSymbols();
XSymbolIndex FindSymbol(u32 _Address);
XSymbolIndex FindSymbol(const char *name);
bool LoadSymbolMap(const char *_rFilename);
void SaveSymbolMap(const char *_rFilename);
void PrintCallstack();
const char *GetDescription(u32 _Address);
bool RenameSymbol(XSymbolIndex _Index, const char *_Name);
void AnalyzeBackwards();
void GetFromAnalyzer();
void MergeMapWithDB(const char *beginning);
struct SCallstackEntry
{
std::string Name;
u32 vAddress;
};
bool GetCallstack(std::vector<SCallstackEntry> &output);
// TODO: move outta here
#ifdef _WIN32
}
#include <windows.h>
#include <windowsx.h>
namespace Debugger
{
void FillSymbolListBox(HWND listbox, ESymbolType symmask);
void FillListBoxBLinks(HWND listbox, XSymbolIndex Index);
#endif
} // end of namespace Debugger
#endif

View File

@ -0,0 +1,87 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <stdio.h>
#include "Common.h"
#include "Dump.h"
CDump::CDump(const char* _szFilename) :
m_pData(NULL),
m_bInit(false)
{
FILE* pStream = fopen(_szFilename, "rb");
if (pStream != NULL)
{
fseek(pStream, 0, SEEK_END);
m_size = ftell(pStream);
fseek(pStream, 0, SEEK_SET);
m_pData = new u8[m_size];
fread(m_pData, m_size, 1, pStream);
fclose(pStream);
}
}
CDump::~CDump(void)
{
if (m_pData != NULL)
{
delete [] m_pData;
m_pData = NULL;
}
}
int
CDump::GetNumberOfSteps(void)
{
return (int)(m_size / STRUCTUR_SIZE);
}
u32
CDump::GetGPR(int _step, int _gpr)
{
u32 offset = _step * STRUCTUR_SIZE;
if (offset >= m_size)
return -1;
return Read32(offset + OFFSET_GPR + (_gpr * 4));
}
u32
CDump::GetPC(int _step)
{
u32 offset = _step * STRUCTUR_SIZE;
if (offset >= m_size)
return -1;
return Read32(offset + OFFSET_PC);
}
u32
CDump::Read32(u32 _pos)
{
u32 result = (m_pData[_pos+0] << 24) |
(m_pData[_pos+1] << 16) |
(m_pData[_pos+2] << 8) |
(m_pData[_pos+3] << 0);
return result;
}

View File

@ -0,0 +1,52 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// uncompress the dumps from costis GC-Debugger tool
//
//
#ifndef _DUMP_H
#define _DUMP_H
#include "Common.h"
class CDump
{
public:
CDump(const char* _szFilename);
~CDump();
int GetNumberOfSteps();
u32 GetGPR(int _step, int _gpr);
u32 GetPC(int _step);
private:
enum
{
OFFSET_GPR = 0x4,
OFFSET_PC = 0x194,
STRUCTUR_SIZE = 0x2BC
};
u8 *m_pData;
bool m_bInit;
size_t m_size;
u32 Read32(u32 _pos);
};
#endif

View File

@ -0,0 +1,109 @@
#ifndef GCELF_H
#define GCELF_H
// ELF File Types
#define ET_NONE 0 // No file type
#define ET_REL 1 // Relocatable file
#define ET_EXEC 2 // Executable file
#define ET_DYN 3 // Shared object file
#define ET_CORE 4 // Core file
#define ET_LOPROC 0xFF00 // Processor specific
#define ET_HIPROC 0xFFFF // Processor specific
// ELF Machine Types
#define EM_NONE 0 // No machine
#define EM_M32 1 // AT&T WE 32100
#define EM_SPARC 2 // SPARC
#define EM_386 3 // Intel Architecture
#define EM_68K 4 // Motorola 68000
#define EM_88K 5 // Motorola 88000
#define EM_860 6 // Intel 80860
#define EM_MIPS 7 // MIPS RS3000 Big-Endian
#define EM_MIPS_RS4_BE 8 // MIPS RS4000 Big-Endian
#define EM_ARM 40 // ARM/Thumb Architecture
// ELF Version Types
#define EV_NONE 0 // Invalid version
#define EV_CURRENT 1 // Current version
// ELF Section Header Types
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
typedef struct
{
unsigned char ID[4];
unsigned char clazz;
unsigned char data;
unsigned char version;
unsigned char pad[9];
unsigned short e_type; // ELF file type
unsigned short e_machine; // ELF target machine
unsigned int e_version; // ELF file version number
unsigned int e_entry;
unsigned int e_phoff;
unsigned int e_shoff;
unsigned int e_flags;
unsigned short e_ehsize;
unsigned short e_phentsize;
unsigned short e_phnum;
unsigned short e_shentsize;
unsigned short e_shnum;
unsigned short e_shtrndx;
} ELF_Header;
typedef struct {
unsigned int type;
unsigned int offset;
unsigned int vaddr;
unsigned int paddr;
unsigned int filesz;
unsigned int memsz;
unsigned int flags;
unsigned int align;
} Program_Header;
typedef struct
{
unsigned int name;
unsigned int type;
unsigned int flags;
unsigned int addr;
unsigned int offset;
unsigned int size;
unsigned int link;
unsigned int info;
unsigned int addralign;
unsigned int entsize;
} Section_Header;
typedef struct {
unsigned int name;
unsigned int value;
unsigned int size;
unsigned char info;
unsigned char other;
unsigned short shndx;
} Symbol_Header;
typedef struct {
unsigned int offset;
unsigned int info;
signed int addend;
} Rela_Header;
const char ELFID[4] = {0x7F, 'E', 'L', 'F'};
#endif

View File

@ -0,0 +1,11 @@
#ifndef _GCLIBLOC_H
#define _GCLIBLOC_H
int LoadSymbolsFromO(const char* filename, unsigned int base, unsigned int count);
void Debugger_LoadSymbolTable(const char* _szFilename);
void Debugger_SaveSymbolTable(const char* _szFilename);
void Debugger_LocateSymbolTables(const char* _szFilename);
void Debugger_ResetSymbolTables();
#endif

View File

@ -0,0 +1,402 @@
//__________________________________________________________________________________________________
//
// GClibloc.c V1.0 by Costis!
// (CONFIDENTIAL VERSION)
//
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "../HLE/HLE.h"
#include "../Host.h"
#include "GCELF.h"
#include "GCLibLoc.h"
#include "../HW/Memmap.h"
#include "Debugger_SymbolMap.h"
#define gELFTypeS(a) (a == ET_NONE ? "NONE" : \
a == ET_REL ? "RELOCATABLE" : \
a == ET_EXEC ? "EXECUTABLE" : \
a == ET_DYN ? "SHARED OBJECT" : \
a == ET_CORE ? "CORE" : \
a == ET_LOPROC ? "PROCESSOR SPECIFIC: LOPROC" : \
a == ET_HIPROC ? "PROCESSOR SPECIFIC: HIPROC" : "INVALID")
inline unsigned int bswap (unsigned int a)
{
return Common::swap32(a);
}
void readSectionHeader (FILE *ifil, int section, ELF_Header ELF_H, Section_Header *ELF_SH)
{
fseek (ifil, ELF_H.e_shoff + ELF_H.e_shentsize * section, SEEK_SET);
fread (ELF_SH, 1, sizeof (Section_Header), ifil);
// Convert the GameCube (Big Endian) format to Little Endian
ELF_SH->name = bswap (ELF_SH->name);
ELF_SH->type = bswap (ELF_SH->type);
ELF_SH->flags = bswap (ELF_SH->flags);
ELF_SH->addr = bswap (ELF_SH->addr);
ELF_SH->offset = bswap (ELF_SH->offset);
ELF_SH->size = bswap (ELF_SH->size);
ELF_SH->link = bswap (ELF_SH->link);
ELF_SH->info = bswap (ELF_SH->info);
ELF_SH->addralign = bswap (ELF_SH->addralign);
ELF_SH->entsize = bswap (ELF_SH->entsize);
}
void readProgramHeader (FILE *ifil, int psection, ELF_Header ELF_H, Program_Header *ELF_PH)
{
fseek (ifil, ELF_H.e_phoff + ELF_H.e_phentsize * psection, SEEK_SET);
fread (ELF_PH, 1, sizeof (Program_Header), ifil);
// Convert the GameCube (Big Endian) format to Little Endian
ELF_PH->type = bswap (ELF_PH->type);
ELF_PH->offset = bswap (ELF_PH->offset);
ELF_PH->vaddr = bswap (ELF_PH->vaddr);
ELF_PH->paddr = bswap (ELF_PH->paddr);
ELF_PH->filesz = bswap (ELF_PH->filesz);
ELF_PH->memsz = bswap (ELF_PH->memsz);
ELF_PH->flags = bswap (ELF_PH->flags);
ELF_PH->align = bswap (ELF_PH->align);
}
unsigned int locShStrTab (FILE *ifil, ELF_Header ELF_H)
{
int i;
Section_Header ELF_SH;
char stID[10];
for (i = 1; i < ELF_H.e_shnum; i++)
{
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
if (ELF_SH.type == SHT_STRTAB)
{
fseek (ifil, ELF_SH.offset + ELF_SH.name, SEEK_SET);
fread (stID, 1, 10, ifil);
if (strcmp (stID, ".shstrtab") == 0)
return ELF_SH.offset;
}
}
return 0;
}
unsigned int locStrTab (FILE *ifil, ELF_Header ELF_H)
{
int i;
Section_Header ELF_SH;
unsigned int ShStrTab;
char stID[10];
// Locate the Section String Table first.
for (i = 1; i < ELF_H.e_shnum; i++)
{
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
if (ELF_SH.type == SHT_STRTAB)
{
fseek (ifil, ELF_SH.offset + ELF_SH.name, SEEK_SET);
fread (stID, 1, 10, ifil);
if (strcmp (stID, ".shstrtab") == 0)
break;
}
}
if (i >= ELF_H.e_shnum)
return 0; // No Section String Table was located.
ShStrTab = ELF_SH.offset;
// Locate the String Table using the Section String Table.
for (i = 1; i < ELF_H.e_shnum; i++)
{
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
if (ELF_SH.type == SHT_STRTAB)
{
fseek (ifil, ShStrTab + ELF_SH.name, SEEK_SET);
fread (stID, 1, 8, ifil);
if (strcmp (stID, ".strtab") == 0)
return ELF_SH.offset;
}
}
return 0; // No String Table was located.
}
unsigned int locStrTabShStrTab (FILE *ifil, unsigned int ShStrTab, ELF_Header ELF_H)
{
int i;
Section_Header ELF_SH;
char stID[8];
for (i = 1; i < ELF_H.e_shnum; i++)
{
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
if (ELF_SH.type == SHT_STRTAB)
{
fseek (ifil, ShStrTab + ELF_SH.name, SEEK_SET);
fread (stID, 1, 8, ifil);
if (strcmp (stID, ".strtab") == 0)
return ELF_SH.offset;
}
}
return 0;
}
unsigned int locSection (FILE *ifil, unsigned int ShType, ELF_Header ELF_H)
{
int i;
Section_Header ELF_SH;
for (i = 1; i < ELF_H.e_shnum; i++)
{
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
if (ELF_SH.type == ShType)
return i;
}
return 0;
}
unsigned int locCode (unsigned char *abuf, unsigned int fsize, unsigned char *bbuf, unsigned int offset, unsigned int size)
{
unsigned int i, j;
unsigned int b;
i = 0;
while (i < fsize)
{
if ((*(unsigned int*)(abuf + i)) == *(unsigned int*)(bbuf + offset))
{
// Code section possibly found.
for (j = 4; j < size; j += 4)
{
b = (*(unsigned int*)(bbuf + offset + j));
if ((*(unsigned int*)(abuf + i + j) != b) && (b != 0))
break;
}
if (j >= size)
return i; // The code section was found.
}
i += 4;
}
return 0;
}
int LoadSymbolsFromO(const char* filename, unsigned int base, unsigned int count)
{
unsigned int i, j;
FILE *ifil;
char astr[64];
unsigned char *abuf, *bbuf;
unsigned int ShStrTab, StrTab, SymTab;
ELF_Header ELF_H;
Section_Header ELF_SH;
Symbol_Header ELF_SYM;
Rela_Header ELF_RELA;
ifil = fopen (filename, "rb");
if (ifil == NULL) return 0;
fread (&ELF_H, 1, sizeof (ELF_Header), ifil);
ELF_H.e_type = (ELF_H.e_type >> 8) | (ELF_H.e_type << 8);
ELF_H.e_machine = (ELF_H.e_machine >> 8) | (ELF_H.e_machine << 8);
ELF_H.e_ehsize = (ELF_H.e_ehsize >> 8) | (ELF_H.e_ehsize << 8);
ELF_H.e_phentsize = (ELF_H.e_phentsize >> 8) | (ELF_H.e_phentsize << 8);
ELF_H.e_phnum = (ELF_H.e_phnum >> 8) | (ELF_H.e_phnum << 8);
ELF_H.e_shentsize = (ELF_H.e_shentsize >> 8) | (ELF_H.e_shentsize << 8);
ELF_H.e_shnum = (ELF_H.e_shnum >> 8) | (ELF_H.e_shnum << 8);
ELF_H.e_shtrndx = (ELF_H.e_shtrndx >> 8) | (ELF_H.e_shtrndx << 8);
ELF_H.e_version = bswap(ELF_H.e_version );
ELF_H.e_entry = bswap(ELF_H.e_entry );
ELF_H.e_phoff = bswap(ELF_H.e_phoff );
ELF_H.e_shoff = bswap(ELF_H.e_shoff );
ELF_H.e_flags = bswap(ELF_H.e_flags );
if (ELF_H.e_machine != 20)
{
printf ("This is not a GameCube ELF file!\n");
return 0;
}
printf ("Identification ID: %c%c%c%c\n", ELF_H.ID[0], ELF_H.ID[1], ELF_H.ID[2], ELF_H.ID[3]);
printf ("ELF Type: %d (%s)\n", ELF_H.e_type, gELFTypeS (ELF_H.e_type));
printf ("ELF Machine: %d\n", ELF_H.e_machine);
printf ("ELF Version: %d\n", ELF_H.e_version);
ShStrTab = locShStrTab (ifil, ELF_H);
fseek (ifil, ShStrTab + 1, SEEK_SET);
fread (astr, 1, 32, ifil);
for (i = 0; i < ELF_H.e_shnum; i++)
{
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
if (ELF_SH.type != 0)
{
fseek (ifil, ShStrTab + ELF_SH.name, SEEK_SET);
j = 0;
while (1)
if ((astr[j++] = fgetc (ifil)) == 0) break;
}
}
StrTab = locStrTab (ifil, ELF_H);
SymTab = locSection (ifil, SHT_SYMTAB, ELF_H);
readSectionHeader (ifil, SymTab, ELF_H, &ELF_SH);
for (i = 1; i < ELF_SH.size / 16; i++)
{
fseek (ifil, ELF_SH.offset + 16 * i, SEEK_SET);
fread (&ELF_SYM, 1, sizeof (Symbol_Header), ifil);
ELF_SYM.name = bswap (ELF_SYM.name);
ELF_SYM.value = bswap (ELF_SYM.value);
ELF_SYM.size = bswap (ELF_SYM.size);
ELF_SYM.shndx = (ELF_SYM.shndx >> 8) | (ELF_SYM.shndx << 8);
fseek (ifil, StrTab + ELF_SYM.name, SEEK_SET);
j = 0;
while (1)
if ((astr[j++] = fgetc (ifil)) == 0) break;
}
readSectionHeader (ifil, 1, ELF_H, &ELF_SH);
fseek (ifil, ELF_SH.offset, SEEK_SET);
if (ELF_SH.size<0 || ELF_SH.size>0x10000000)
{
PanicAlert("WTF??");
}
abuf = (unsigned char *)malloc (ELF_SH.size);
fread (abuf, 1, ELF_SH.size, ifil);
//printf ("\nRelocatable Addend Header Information:\n\n");
readSectionHeader (ifil, locSection (ifil, 4, ELF_H), ELF_H, &ELF_SH);
if (ELF_SH.entsize==0) //corrupt file?
{
char temp[256];
sprintf(temp,"Huh? ELF_SH.entsize==0 in %s!",filename);
//MessageBox(GetForegroundWindow(),temp,"Hmm....",0);
return 0;
}
else
{
unsigned int num = ELF_SH.size / ELF_SH.entsize;
for (i = 0; i < num; i++)
{
fseek (ifil, ELF_SH.offset + 12 * i, SEEK_SET);
fread (&ELF_RELA, 1, sizeof (Rela_Header), ifil);
ELF_RELA.offset = bswap (ELF_RELA.offset);
ELF_RELA.info = bswap (ELF_RELA.info);
ELF_RELA.addend = bswap (ELF_RELA.addend);
*(unsigned int*)(abuf + (ELF_RELA.offset & ~3)) = 0;
if (ELF_SH.size == 0 || ELF_SH.entsize==0) //corrupt file?
{
char temp[256];
sprintf(temp,"Huh? ELF_SH.entsize==0 in %s!",filename);
//MessageBox(GetForegroundWindow(),temp,"Hmm....",0);
return 0;
}
}
bbuf = (unsigned char*)Memory::GetPointer(base);
readSectionHeader (ifil, SymTab, ELF_H, &ELF_SH);
for (i = 1; i < ELF_SH.size / 16; i++)
{
fseek (ifil, ELF_SH.offset + 16 * i, SEEK_SET);
fread (&ELF_SYM, 1, sizeof (Symbol_Header), ifil);
ELF_SYM.name = bswap (ELF_SYM.name);
ELF_SYM.value = bswap (ELF_SYM.value);
ELF_SYM.size = bswap (ELF_SYM.size);
ELF_SYM.shndx = (ELF_SYM.shndx >> 8) | (ELF_SYM.shndx << 8);
if (ELF_SYM.shndx == 1)
{
fseek (ifil, StrTab + ELF_SYM.name, SEEK_SET);
j = 0;
while (1)
{
if ((astr[j++] = fgetc (ifil)) == 0)
break;
}
u32 offset = locCode (bbuf, count, abuf, ELF_SYM.value, ELF_SYM.size);
if (offset != 0 && ELF_SYM.size>12)
{
Debugger::AddSymbol(Debugger::CSymbol(offset+base | 0x80000000, ELF_SYM.size, Debugger::ST_FUNCTION, astr));
}
}
}
free (abuf);
fclose (ifil);
}
return 0;
}
void Debugger_LoadSymbolTable(const char* _szFilename)
{
Debugger::LoadSymbolMap(_szFilename);
HLE::PatchFunctions();
Host_NotifyMapLoaded();
}
void Debugger_SaveSymbolTable(const char* _szFilename)
{
Debugger::SaveSymbolMap(_szFilename);
}
void Debugger_LocateSymbolTables(const char* _szFilename)
{
std::vector<std::string> files;
std::string directory = _szFilename;
const char *temp = _szFilename;
const char *oldtemp = temp;
temp += strlen(temp)+1;
if (*temp==0)
{
//we only got one file
files.push_back(std::string(oldtemp));
}
else
{
while (*temp)
{
files.push_back(directory + _T("\\") + _T(temp));
temp+=strlen(temp)+1;
}
}
while(!files.empty())
{
std::string strFilename = files.back();
files.pop_back();
LOG(MASTER_LOG,"Loading symbols from %s", strFilename.c_str());
LoadSymbolsFromO(strFilename.c_str(), 0x80000000, 24*1024*1024);
}
HLE::PatchFunctions();
}
void Debugger_ResetSymbolTables()
{
// this shouldn't work, because we have to de-patch HLE too and that is not possible
// Well, de-patching hle would be possible if we saved away the old code bytes :P
// It's not like we use much HLE now anyway -ector
Debugger::Reset();
Host_NotifyMapLoaded();
}

View File

@ -0,0 +1,104 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Debugger_BreakPoints.h"
#include "Debugger_SymbolMap.h"
#include "DebugInterface.h"
#include "PPCDebugInterface.h"
#include "PowerPCDisasm.h"
#include "../Core.h"
#include "../HW/Memmap.h"
#include "../PowerPC/PowerPC.h"
// Not thread safe.
const char *PPCDebugInterface::disasm(unsigned int address)
{
if (Core::GetState() != Core::CORE_UNINITIALIZED)
{
if (Memory::IsRAMAddress(address))
{
u32 op = Memory::Read_Instruction(address);
return DisassembleGekko(op, address);
}
return "No RAM here - invalid";
}
static const char tmp[] = "<unknown>";
return tmp;
}
unsigned int PPCDebugInterface::readMemory(unsigned int address)
{
return Memory::ReadUnchecked_U32(address);
}
bool PPCDebugInterface::isAlive()
{
return Core::GetState() != Core::CORE_UNINITIALIZED;
}
bool PPCDebugInterface::isBreakpoint(unsigned int address)
{
return CBreakPoints::IsAddressBreakPoint(address);
}
void PPCDebugInterface::setBreakpoint(unsigned int address)
{
CBreakPoints::AddBreakPoint(address);
}
void PPCDebugInterface::clearBreakpoint(unsigned int address)
{
CBreakPoints::RemoveBreakPoint(address);
}
void PPCDebugInterface::clearAllBreakpoints() {}
void PPCDebugInterface::toggleBreakpoint(unsigned int address)
{
CBreakPoints::IsAddressBreakPoint(address)?CBreakPoints::RemoveBreakPoint(address):CBreakPoints::AddBreakPoint(address);
}
int PPCDebugInterface::getColor(unsigned int address)
{
if (!Memory::IsRAMAddress(address))
return 0xeeeeee;
int colors[6] = {0xe0FFFF,0xFFe0e0,0xe8e8FF,0xFFe0FF,0xe0FFe0,0xFFFFe0};
int n = Debugger::FindSymbol(address);
if (n == -1) return 0xFFFFFF;
return colors[n%6];
}
std::string PPCDebugInterface::getDescription(unsigned int address)
{
return Debugger::GetDescription(address);
}
unsigned int PPCDebugInterface::getPC()
{
return PowerPC::ppcState.pc;
}
void PPCDebugInterface::setPC(unsigned int address)
{
PowerPC::ppcState.pc = address;
}
void PPCDebugInterface::runToBreakpoint()
{
}

View File

@ -0,0 +1,29 @@
#ifndef _PPCDEBUGINTERFACE_H
#define _PPCDEBUGINTERFACE_H
#include <string>
//wrapper between disasm control and Dolphin debugger
class PPCDebugInterface : public DebugInterface
{
public:
PPCDebugInterface(){}
virtual const char *disasm(unsigned int address);
virtual int getInstructionSize(int instruction) {return 4;}
virtual bool isAlive();
virtual bool isBreakpoint(unsigned int address);
virtual void setBreakpoint(unsigned int address);
virtual void clearBreakpoint(unsigned int address);
virtual void clearAllBreakpoints();
virtual void toggleBreakpoint(unsigned int address);
virtual unsigned int readMemory(unsigned int address);
virtual unsigned int getPC();
virtual void setPC(unsigned int address);
virtual void step() {}
virtual void runToBreakpoint();
virtual int getColor(unsigned int address);
virtual std::string getDescription(unsigned int address);
};
#endif

View File

@ -0,0 +1,118 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
/////////////////////////////////////////////////////////////////////////////////////////////////////
// M O D U L E B E G I N ///////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
/////////////////////////////////////////////////////////////////////////////////////////////////////
// C L A S S/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
class CDolLoader
{
public:
CDolLoader(const char* _szFilename) :
m_bInit(false)
{
// try to open file
FILE* pStream = NULL;
fopen_s(&pStream, _szFilename, "rb");
if (pStream)
{
fread(&m_dolheader, 1, sizeof(SDolHeader), pStream);
// swap memory
DWORD* p = (DWORD*)&m_dolheader;
for (int i=0; i<(sizeof(SDolHeader)>>2); i++)
p[i] = Common::swap32(p[i]);
// load all text (code) sections
for(int i=0; i<DOL_NUM_TEXT; i++)
{
if(m_dolheader.textOffset[i] != 0)
{
BYTE* pTemp = new BYTE[m_dolheader.textSize[i]];
fseek(pStream, m_dolheader.textOffset[i], SEEK_SET);
fread(pTemp, 1, m_dolheader.textSize[i], pStream);
for (size_t num=0; num<m_dolheader.textSize[i]; num++)
CMemory::Write_U8(pTemp[num], m_dolheader.textAddress[i] + num);
delete [] pTemp;
}
}
// load all data sections
for(int i=0; i<DOL_NUM_DATA; i++)
{
if(m_dolheader.dataOffset[i] != 0)
{
BYTE* pTemp = new BYTE[m_dolheader.dataSize[i]];
fseek(pStream, m_dolheader.dataOffset[i], SEEK_SET);
fread(pTemp, 1, m_dolheader.dataSize[i], pStream);
for (size_t num=0; num<m_dolheader.dataSize[i]; num++)
CMemory::Write_U8(pTemp[num], m_dolheader.dataAddress[i] + num);
delete [] pTemp;
}
}
fclose(pStream);
m_bInit = true;
}
}
_u32 GetEntryPoint(void)
{
return m_dolheader.entryPoint;
}
private:
enum
{
DOL_NUM_TEXT = 7,
DOL_NUM_DATA = 11
};
struct SDolHeader
{
_u32 textOffset[DOL_NUM_TEXT];
_u32 dataOffset[DOL_NUM_DATA];
_u32 textAddress[DOL_NUM_TEXT];
_u32 dataAddress[DOL_NUM_DATA];
_u32 textSize[DOL_NUM_TEXT];
_u32 dataSize[DOL_NUM_DATA];
_u32 bssAddress;
_u32 bssSize;
_u32 entryPoint;
_u32 padd[7];
};
SDolHeader m_dolheader;
bool m_bInit;
};

View File

@ -0,0 +1,122 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "HLE.h"
#include "../PowerPC/PowerPC.h"
#include "../HW/Memmap.h"
#include "../Debugger/Debugger_SymbolMap.h"
#include "../Debugger/Debugger_BreakPoints.h"
#include "HLE_OS.h"
#include "HLE_Misc.h"
namespace HLE
{
using namespace PowerPC;
typedef void (*TPatchFunction)();
enum
{
HLE_RETURNTYPE_BLR = 0,
HLE_RETURNTYPE_RFI = 1,
};
struct SPatch
{
char m_szPatchName[128];
TPatchFunction PatchFunction;
int returnType;
};
SPatch OSPatches[] =
{
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
// speedup
{ "OSProtectRange", HLE_Misc::UnimplementedFunctionFalse },
// { "THPPlayerGetState", HLE_Misc:THPPlayerGetState },
// Debugout is very nice .)
{ "OSReport", HLE_OS::HLE_OSReport },
{ "OSPanic", HLE_OS::HLE_OSPanic },
{ "vprintf", HLE_OS::HLE_vprintf },
{ "printf", HLE_OS::HLE_printf },
// wii only
{ "SCCheckStatus", HLE_Misc::UnimplementedFunctionFalse }, // SC is SystemConfig ... dunn
// special
// { "GXPeekZ", HLE_Misc::GXPeekZ},
// { "GXPeekARGB", HLE_Misc::GXPeekARGB},
};
SPatch OSBreakPoints[] =
{
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
//{ "__OSInitAudioSystem", CHLE_Audio::__OSInitAudioSystem },
};
void PatchFunctions(const char* _gameID)
{
for (u32 i=0; i < sizeof(OSPatches) / sizeof(SPatch); i++)
{
int SymbolIndex = Debugger::FindSymbol(OSPatches[i].m_szPatchName);
if (SymbolIndex > 0)
{
const Debugger::CSymbol& rSymbol = Debugger::GetSymbol(SymbolIndex);
u32 HLEPatchValue = (1 & 0x3f) << 26;
Memory::Write_U32(HLEPatchValue | i, rSymbol.vaddress);
LOG(HLE,"Patching %s %08x", OSPatches[i].m_szPatchName, rSymbol.vaddress);
}
}
for (size_t i=1; i < sizeof(OSBreakPoints) / sizeof(SPatch); i++)
{
int SymbolIndex = Debugger::FindSymbol(OSBreakPoints[i].m_szPatchName);
if (SymbolIndex != -1)
{
const Debugger::CSymbol& rSymbol = Debugger::GetSymbol(SymbolIndex);
CBreakPoints::AddBreakPoint(rSymbol.vaddress, false);
LOG(HLE,"Adding BP to %s %08x", OSBreakPoints[i].m_szPatchName, rSymbol.vaddress);
}
}
// CBreakPoints::AddBreakPoint(0x8000D3D0, false);
}
void Execute(u32 _CurrentPC, u32 _Instruction)
{
int FunctionIndex = _Instruction & 0xFFFFF;
if ((FunctionIndex > 0) && (FunctionIndex < (sizeof(OSPatches) / sizeof(SPatch))))
{
OSPatches[FunctionIndex].PatchFunction();
}
else
{
_dbg_assert_(HLE, 0);
}
// _dbg_assert_msg_(HLE,NPC == LR, "Broken HLE function (doesn't set NPC)", OSPatches[pos].m_szPatchName);
}
}

View File

@ -0,0 +1,30 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _HLE_H
#define _HLE_H
#include "Common.h"
namespace HLE
{
void PatchFunctions(const char* _gameID = 0);
void Execute(u32 _CurrentPC, u32 _Instruction);
}
#endif

View File

@ -0,0 +1,61 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "HLE_OS.h"
#include "../PowerPC/PowerPC.h"
#include "../HW/Memmap.h"
namespace HLE_Misc
{
void UnimplementedFunction()
{
NPC = LR;
}
void UnimplementedFunctionTrue()
{
GPR(3)=1;
NPC = LR;
}
void UnimplementedFunctionFalse()
{
GPR(3)=0;
NPC = LR;
}
void THPPlayerGetState()
{
GPR(3)=3; // Video played
NPC=LR;
}
void GXPeekZ()
{
Memory::Write_U32(0xFFFFFF,GPR(5));
NPC=LR;
}
void GXPeekARGB()
{
Memory::Write_U32(0xFFFFFFFF,GPR(5));
NPC=LR;
}
}

View File

@ -0,0 +1,32 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef HLE_MISC_H
#define HLE_MISC_H
namespace HLE_Misc
{
void Pass();
void UnimplementedFunction();
void UnimplementedFunctionTrue();
void UnimplementedFunctionFalse();
void THPPlayerGetState();
void GXPeekZ();
void GXPeekARGB();
}
#endif

View File

@ -0,0 +1,127 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "StringUtil.h"
#include <string>
#include "Common.h"
#include "HLE_OS.h"
#include "../PowerPC/PowerPC.h"
#include "../HW/Memmap.h"
namespace HLE_OS
{
void GetStringVA(std::string& _rOutBuffer);
void HLE_OSPanic()
{
std::string Error;
GetStringVA(Error);
PanicAlert("PanicAlert: %s", Error.c_str());
LOG(HLE,"(PC=%08x), PanicAlert: %s", LR, Error.c_str());
NPC = LR;
}
void HLE_OSReport()
{
std::string ReportMessage;
GetStringVA(ReportMessage);
LOG(HLE,"(PC=%08x) OSReport: %s", LR, ReportMessage.c_str());
NPC = LR;
}
void HLE_vprintf()
{
std::string ReportMessage;
GetStringVA(ReportMessage);
LOG(HLE,"(PC=%08x) VPrintf: %s", LR, ReportMessage.c_str());
NPC = LR;
}
void HLE_printf()
{
std::string ReportMessage;
GetStringVA(ReportMessage);
LOG(HLE,"(PC=%08x) Printf: %s ", LR, ReportMessage.c_str());
NPC = LR;
}
void GetStringVA(std::string& _rOutBuffer)
{
char ArgumentBuffer[256];
u32 ParameterCounter = 4;
char* pString = (char*)Memory::GetPointer(GPR(3));
while(*pString)
{
if (*pString == '%')
{
char* pArgument = ArgumentBuffer;
*pArgument++ = *pString++;
while(*pString < 'A' || *pString > 'z' || *pString == 'l' || *pString == '-')
*pArgument++ = *pString++;
*pArgument++ = *pString;
*pArgument = NULL;
u32 Parameter;
if (ParameterCounter > 10)
{
Parameter = Memory::Read_U32(GPR(1) + 0x8 + ((ParameterCounter - 11) * 4));
}
else
{
Parameter = GPR(ParameterCounter);
}
ParameterCounter++;
switch(*pString)
{
case 's':
_rOutBuffer += StringFromFormat(ArgumentBuffer, (char*)Memory::GetPointer(Parameter));
break;
case 'd':
{
//u64 Double = Memory::Read_U64(Parameter);
_rOutBuffer += StringFromFormat(ArgumentBuffer, Parameter);
}
break;
default:
_rOutBuffer += StringFromFormat(ArgumentBuffer, Parameter);
break;
}
pString++;
}
else
{
_rOutBuffer += StringFromFormat("%c", *pString);
pString++;
}
}
}
}

View File

@ -0,0 +1,31 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef HLE_OS_H
#define HLE_OS_H
#include "Common.h"
namespace HLE_OS
{
void HLE_vprintf();
void HLE_printf();
void HLE_OSReport();
void HLE_OSPanic();
}
#endif

View File

@ -0,0 +1,329 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "StreamADPCM.H"
#include "AudioInterface.h"
#include "CPU.h"
#include "PeripheralInterface.h"
#include "DVDInterface.h"
#include "../PowerPC/PowerPC.h"
#include "../CoreTiming.h"
#include "../HW/SystemTimers.h"
namespace AudioInterface
{
// internal hardware addresses
enum
{
AI_CONTROL_REGISTER = 0x6C00,
AI_VOLUME_REGISTER = 0x6C04,
AI_SAMPLE_COUNTER = 0x6C08,
AI_INTERRUPT_TIMING = 0x6C0C,
};
// AI Control Register
union AICR
{
AICR() { hex = 0;}
AICR(u32 _hex) { hex = _hex;}
struct
{
unsigned PSTAT : 1; // sample counter/playback enable
unsigned AFR : 1; // 0=32khz 1=48khz
unsigned AIINTMSK : 1; // 0=interrupt masked 1=interrupt enabled
unsigned AIINT : 1; // audio interrupt status
unsigned AIINTVLD : 1; // This bit controls whether AIINT is affected by the AIIT register
// matching AISLRCNT. Once set, AIINT will hold
unsigned SCRESET : 1; // write to reset counter
unsigned DSPFR : 1; // DSP Frequency (0=32khz 1=48khz)
unsigned :25;
};
u32 hex;
};
// AI m_Volume Register
union AIVR
{
struct
{
unsigned leftVolume : 8;
unsigned rightVolume : 8;
unsigned : 16;
};
u32 hex;
};
// AudioInterface-Registers
struct SAudioRegister
{
AICR m_Control;
AIVR m_Volume;
u32 m_SampleCounter;
u32 m_InterruptTiming;
};
SAudioRegister g_AudioRegister;
void GenerateAudioInterrupt();
void UpdateInterrupts();
void IncreaseSampleCount(const u32 _uAmount);
void ReadStreamBlock(short* _pPCM);
static u64 g_LastCPUTime = 0;
static int g_SampleRate = 32000;
static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL;
void Init()
{
g_AudioRegister.m_SampleCounter = 0;
g_AudioRegister.m_Control.AFR = 1;
}
void Shutdown()
{
}
void Read32(u32& _rReturnValue, const u32 _Address)
{
//__AI_SRC_INIT compares CC006C08 to zero, loops if 2
switch (_Address & 0xFFFF)
{
case AI_CONTROL_REGISTER: //0x6C00
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
_rReturnValue = g_AudioRegister.m_Control.hex;
return;
// Sample Rate (AIGetDSPSampleRate)
// 32bit state (highest bit PlayState) // AIGetStreamPlayState
case AI_VOLUME_REGISTER: //0x6C04
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
_rReturnValue = g_AudioRegister.m_Volume.hex;
return;
case AI_SAMPLE_COUNTER: //0x6C08
_rReturnValue = g_AudioRegister.m_SampleCounter;
if (g_AudioRegister.m_Control.PSTAT)
g_AudioRegister.m_SampleCounter++; // FAKE: but this is a must
return;
case AI_INTERRUPT_TIMING:
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
_rReturnValue = g_AudioRegister.m_InterruptTiming;
return;
default:
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
_dbg_assert_msg_(AUDIO_INTERFACE,0,"AudioInterface - Read from ???");
_rReturnValue = 0;
return;
}
}
void Write32(const u32 _Value, const u32 _Address)
{
switch (_Address & 0xFFFF)
{
case AI_CONTROL_REGISTER:
{
AICR tmpAICtrl(_Value);
g_AudioRegister.m_Control.AIINTMSK = tmpAICtrl.AIINTMSK;
g_AudioRegister.m_Control.AIINTVLD = tmpAICtrl.AIINTVLD;
// Set frequency
if (tmpAICtrl.AFR != g_AudioRegister.m_Control.AFR)
{
LOG(AUDIO_INTERFACE, "Change Freq to %s", tmpAICtrl.AFR ? "48khz":"32khz");
g_AudioRegister.m_Control.AFR = tmpAICtrl.AFR;
}
g_SampleRate = g_AudioRegister.m_Control.AFR ? 48000 : 32000;
g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_SampleRate;
// Streaming counter
if (tmpAICtrl.PSTAT != g_AudioRegister.m_Control.PSTAT)
{
LOG(AUDIO_INTERFACE, "Change StreamingCounter to %s", tmpAICtrl.PSTAT ? "startet":"stopped");
g_AudioRegister.m_Control.PSTAT = tmpAICtrl.PSTAT;
g_LastCPUTime = CoreTiming::GetTicks();
}
// AI Interrupt
if (tmpAICtrl.AIINT)
{
LOG(AUDIO_INTERFACE, "Clear AI Interrupt");
g_AudioRegister.m_Control.AIINT = 0;
}
// Sample Count Reset
if (tmpAICtrl.SCRESET)
{
LOG(AUDIO_INTERFACE, "Reset SampleCounter");
g_AudioRegister.m_SampleCounter = 0;
g_AudioRegister.m_Control.SCRESET = 0;
// set PSTAT = 0 too ? at least the reversed look like this
g_LastCPUTime = CoreTiming::GetTicks();
}
UpdateInterrupts();
}
break;
case AI_VOLUME_REGISTER:
g_AudioRegister.m_Volume.hex = _Value;
LOG(AUDIO_INTERFACE, "Set m_Volume: left(%i) right(%i)", g_AudioRegister.m_Volume.leftVolume, g_AudioRegister.m_Volume.rightVolume);
break;
case AI_SAMPLE_COUNTER:
_dbg_assert_msg_(AUDIO_INTERFACE,0,"AudioInterface - m_SampleCounter is Read only");
break;
case AI_INTERRUPT_TIMING:
g_AudioRegister.m_InterruptTiming = _Value;
LOG(AUDIO_INTERFACE, "Set AudioInterrupt: 0x%08x Samples", g_AudioRegister.m_InterruptTiming);
break;
default:
PanicAlert("AudioInterface unknown write");
_dbg_assert_msg_(AUDIO_INTERFACE,0,"AudioInterface - Write to ??? %08x", _Address);
break;
}
}
void UpdateInterrupts()
{
if (g_AudioRegister.m_Control.AIINT & g_AudioRegister.m_Control.AIINTMSK)
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_AUDIO, true);
}
else
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_AUDIO, false);
}
}
void GenerateAudioInterrupt()
{
g_AudioRegister.m_Control.AIINT = 1;
UpdateInterrupts();
}
// Callback for the DSP streaming
// WARNING - called from audio thread
unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _numSamples)
{
if (g_AudioRegister.m_Control.PSTAT && !CCPU::IsStepping())
{
static int pos = 0;
static short pcm[28*2];
const int lvolume = g_AudioRegister.m_Volume.leftVolume;
const int rvolume = g_AudioRegister.m_Volume.rightVolume;
for (unsigned int i=0; i<_numSamples; i++)
{
if (pos==0)
{
ReadStreamBlock(pcm);
}
*_pDestBuffer++ = (pcm[pos*2] * lvolume) >> 8;
*_pDestBuffer++ = (pcm[pos*2+1] * rvolume) >> 8;
pos++;
if (pos == 28)
{
pos=0;
}
}
}
else
{
for (unsigned int i=0; i<_numSamples*2; i++)
{
_pDestBuffer[i] = 0; //silence!
}
}
return _numSamples;
}
// WARNING - called from audio thread
void ReadStreamBlock(short* _pPCM)
{
char tempADPCM[32];
if (DVDInterface::DVDReadADPCM((u8*)tempADPCM, 32))
{
NGCADPCM::DecodeBlock(_pPCM, (u8*)tempADPCM);
}
else
{
for (int j=0; j<28; j++)
{
*_pPCM++ = 0;
*_pPCM++ = 0;
}
}
// COMMENT:
// 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.
// IncreaseSampleCount(28);
}
void IncreaseSampleCount(const u32 _iAmount)
{
if (g_AudioRegister.m_Control.PSTAT)
{
g_AudioRegister.m_SampleCounter += _iAmount;
if (g_AudioRegister.m_Control.AIINTVLD &&
(g_AudioRegister.m_SampleCounter > g_AudioRegister.m_InterruptTiming))
{
GenerateAudioInterrupt();
}
}
}
u32 GetRate()
{
return g_SampleRate;
}
void Update()
{
// update timer
if (g_AudioRegister.m_Control.PSTAT)
{
const u64 Diff = CoreTiming::GetTicks() - g_LastCPUTime;
if (Diff > g_CPUCyclesPerSample)
{
const u32 Samples = static_cast<u32>(Diff / g_CPUCyclesPerSample);
g_LastCPUTime += Samples * g_CPUCyclesPerSample;
IncreaseSampleCount(Samples);
}
}
}
} // end of namespace AudioInterface

View File

@ -0,0 +1,47 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _AUDIOINTERFACE_H
#define _AUDIOINTERFACE_H
namespace AudioInterface
{
// Init
void Init();
// Shutdown
void Shutdown();
// Update
void Update();
// Calls by DSP plugin
unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _numSamples);
// Read32
void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
// Write32
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
// Get the Audio Rate (48000 or 32000)
u32 GetRate();
} // end of namespace AudioInterface
#endif

View File

@ -0,0 +1,237 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "Thread.h"
#include "../PowerPC/PowerPC.h"
#include "../Host.h"
#include "../Core.h"
#include "CPU.h"
#include "CPUCompare.h"
#include "../Debugger/Debugger_BreakPoints.h"
using namespace PowerPC;
namespace {
bool g_Branch;
Common::Event m_StepEvent;
Common::Event *m_SyncEvent;
}
void CCPU::Init()
{
m_StepEvent.Init();
PowerPC::Init();
m_SyncEvent = 0;
}
void CCPU::Shutdown()
{
PowerPC::Shutdown();
m_StepEvent.Shutdown();
m_SyncEvent = 0;
}
void CCPU::Run()
{
Host_UpdateDisasmDialog();
while (true)
{
switch(PowerPC::state) {
case CPU_RUNNING:
//1: enter a fast runloop
PowerPC::RunLoop();
break;
case CPU_RUNNINGDEBUG:
//1: check for cpucompare
/*
if (CPUCompare::IsEnabled() && g_Branch)
{
g_Branch = false;
CPUCompare::Sync();
}*/
//2: check for breakpoint
if (CBreakPoints::IsAddressBreakPoint(PC))
{
LOG(GEKKO, "Hit Breakpoint - %08x", PC);
EnableStepping(true);
if (CBreakPoints::IsTempBreakPoint(PC))
CBreakPoints::RemoveBreakPoint(PC);
Host_UpdateDisasmDialog();
break;
}
/* if (!Core::g_CoreStartupParameter.bUseDynarec && CBreakPoints::GetBreakCount() == PowerPC::ppcState.DebugCount)
{
LOG(GEKKO, "Hit DebugCount breakpoint - %i", PowerPC::ppcState.DebugCount);
EnableStepping(true);
break;
}*/
//3: do a step
PowerPC::SingleStep();
break;
case CPU_STEPPING:
//1: wait for step command..
m_StepEvent.Wait();
if (state == CPU_POWERDOWN)
return;
//2: check for cpu compare
if (CPUCompare::IsEnabled() && g_Branch)
{
g_Branch = false;
CPUCompare::Sync();
}
//3: do a step
PowerPC::SingleStep();
//4: update disasm dialog
if (m_SyncEvent) {
m_SyncEvent->Set();
m_SyncEvent = 0;
}
Host_UpdateDisasmDialog();
break;
case CPU_POWERDOWN:
//1: Exit loop!!
return;
}
}
}
void CCPU::Stop()
{
PowerPC::Stop();
m_StepEvent.Set();
}
bool CCPU::IsStepping()
{
return PowerPC::state == CPU_STEPPING;
}
void CCPU::Reset()
{
}
void CCPU::StepOpcode(Common::Event *event)
{
m_StepEvent.Set();
if (PowerPC::state == CPU_STEPPING)
{
m_SyncEvent = event;
}
}
void CCPU::EnableStepping(const bool _bStepping)
{
if (_bStepping)
{
PowerPC::Pause();
// TODO(ector): why a sleep?
Host_SetDebugMode(true);
}
else
{
Host_SetDebugMode(false);
PowerPC::Start();
m_StepEvent.Set();
}
}
void CCPU::SingleStep()
{
switch (PowerPC::state)
{
case CPU_RUNNING:
//1: enter a fast runloop
PowerPC::RunLoop();
break;
case CPU_RUNNINGDEBUG:
//1: check for cpucompare
if (CPUCompare::IsEnabled() && g_Branch)
{
g_Branch = false;
CPUCompare::Sync();
}
//2: check for breakpoint
if (CBreakPoints::IsAddressBreakPoint(PC))
{
LOG(GEKKO, "Hit Breakpoint - %08x", PC);
EnableStepping(true);
if (CBreakPoints::IsTempBreakPoint(PC))
CBreakPoints::RemoveBreakPoint(PC);
break;
}
if (!Core::g_CoreStartupParameter.bUseDynarec && CBreakPoints::GetBreakCount() == PowerPC::ppcState.DebugCount)
{
LOG(GEKKO, "Hit DebugCount breakpoint - %i", PowerPC::ppcState.DebugCount);
EnableStepping(true);
break;
}
//3: do a step
PowerPC::SingleStep();
break;
case CPU_STEPPING:
//1: wait for step command..
m_StepEvent.Wait();
//2: check for cpu compare
if (CPUCompare::IsEnabled() && g_Branch)
{
g_Branch = false;
CPUCompare::Sync();
}
//3: do a step
PowerPC::SingleStep();
//4: update disasm dialog
if (m_SyncEvent) {
m_SyncEvent->Set();
m_SyncEvent = 0;
}
Host_UpdateDisasmDialog();
break;
case CPU_POWERDOWN:
//1: Exit loop!!
return;
}
}
void CCPU::Break()
{
EnableStepping(true);
}

View File

@ -0,0 +1,60 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _CPU_H
#define _CPU_H
#include "Common.h"
namespace Common {
class Event;
}
class CCPU
{
public:
// init
static void Init();
// shutdown
static void Shutdown();
// starts the CPU
static void Run();
// causes shutdown
static void Stop();
// Reset
static void Reset();
// StepOpcode (Steps one Opcode)
static void StepOpcode(Common::Event *event = 0);
// one step only
static void SingleStep();
// Enable or Disable Stepping
static void EnableStepping(const bool _bStepping);
// is stepping ?
static bool IsStepping();
// break
static void Break();
};
#endif

View File

@ -0,0 +1,246 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifdef _WIN32
#include <windows.h>
#endif
#include "Common.h"
#include "../Core.h"
#include "CPUCompare.h"
#include "../PowerPC/PowerPC.h"
#include "CommandProcessor.h"
#include "../Host.h"
#ifdef _WIN32
namespace CPUCompare
{
HANDLE m_hPipe;
bool m_bIsServer;
bool m_bEnabled;
u32 m_BlockStart;
#define PIPENAME "\\\\.\\pipe\\cpucompare"
int stateSize = 32*4 + 32*16 + 6*4;
void SetBlockStart(u32 addr)
{
m_BlockStart = addr;
}
void StartServer()
{
_assert_msg_(GEKKO, Core::GetStartupParameter().bUseDualCore != true, "Don't use multithreading together with CPU-compare.");
if (m_bEnabled)
return;
//TODO: error checking
m_hPipe = CreateNamedPipe(
PIPENAME,
PIPE_ACCESS_OUTBOUND,
PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
1, //maxinst
0x1000, //outbufsize
0x1000, //inbufsize
INFINITE, //timeout
0);
_assert_msg_(GEKKO, m_hPipe != INVALID_HANDLE_VALUE, "Failed to create pipe.");
//_assert_msg_(GEKKO, 0, "Pipe %s created.", PIPENAME);
m_bIsServer = true;
m_bEnabled = true;
}
void ConnectAsClient()
{
_assert_msg_(GEKKO, Core::GetStartupParameter().bUseDualCore != true, "Don't use multithreading together with CPU-compare.");
if (m_bEnabled)
return;
//TODO: error checking
m_hPipe = CreateFile(
PIPENAME,
GENERIC_READ,
0, //share
NULL,
OPEN_EXISTING,
0,
NULL);
_assert_msg_(GEKKO, m_hPipe != INVALID_HANDLE_VALUE, "Failed to connect to pipe. %08x (2 = file not found)", GetLastError());
m_bEnabled = true;
m_bIsServer = false;
}
void Stop()
{
if (m_bEnabled)
{
if (m_bIsServer)
{
DisconnectNamedPipe(m_hPipe);
CloseHandle(m_hPipe);
}
else
{
CloseHandle(m_hPipe); //both for server and client i guess
}
m_bEnabled=false;
}
}
int Sync()
{
_assert_msg_(GEKKO,0,"Sync - PC = %08x", PC);
PowerPC::PowerPCState state;
if (!m_bEnabled)
return 0;
if (m_bIsServer) //This should be interpreter
{
//write cpu state to m_hPipe
HRESULT result;
u32 written;
// LogManager::Redraw();
result = WriteFile(m_hPipe, &PowerPC::ppcState, stateSize, (LPDWORD)&written,FALSE);
//_assert_msg_(GEKKO, 0, "Server Wrote!");
if (FAILED(result))
{
_assert_msg_(GEKKO,0,"Failed to write cpu state to named pipe");
Stop();
}
// LogManager::Redraw();
}
else //This should be dynarec
{
u32 read;
memset(&state,0xcc,stateSize);
BOOL res = ReadFile(m_hPipe, &state, stateSize, (LPDWORD)&read, FALSE);
//_assert_msg_(GEKKO, 0, "Client got data!");
//read cpu state to m_hPipe and compare
//if any errors, print report
if (!res || read != stateSize)
{
_assert_msg_(GEKKO,0,"Failed to read cpu state from named pipe");
Stop();
}
else
{
bool difference = false;
for (int i=0; i<32; 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]);
difference = true;
}
}
for (int i=0; i<32; i++)
{
for (int j=0; j<2; 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]);
difference = true;
}
}
}
if (PowerPC::ppcState.cr != state.cr)
{
LOG(GEKKO, "DIFFERENCE - CR (local %08x, remote %08x)", PowerPC::ppcState.cr, state.cr);
difference = true;
}
if (PowerPC::ppcState.pc != state.pc)
{
LOG(GEKKO, "DIFFERENCE - PC (local %08x, remote %08x)", PowerPC::ppcState.pc, state.pc);
difference = true;
}
//if (PowerPC::ppcState.npc != state.npc)
///{
// LOG(GEKKO, "DIFFERENCE - NPC (local %08x, remote %08x)", PowerPC::ppcState.npc, state.npc);
// difference = true;
//}
if (PowerPC::ppcState.msr != state.msr)
{
LOG(GEKKO, "DIFFERENCE - MSR (local %08x, remote %08x)", PowerPC::ppcState.msr, state.msr);
difference = true;
}
if (PowerPC::ppcState.fpscr != state.fpscr)
{
LOG(GEKKO, "DIFFERENCE - FPSCR (local %08x, remote %08x)", PowerPC::ppcState.fpscr, state.fpscr);
difference = true;
}
if (difference)
{
Host_UpdateLogDisplay();
//Also show drec compare window here
//CDynaViewDlg::Show(true);
//CDynaViewDlg::ViewAddr(m_BlockStart);
//CDynaViewDlg::Show(true);
//Sleep(INFINITE);
return false;
}
else
{
return true;
//LOG(GEKKO, "No difference!");
}
}
}
return 0;
}
bool IsEnabled()
{
return m_bEnabled;
}
bool IsServer()
{
return m_bIsServer;
}
}
#else
namespace CPUCompare
{
void StartServer() { }
void ConnectAsClient() { }
void Stop() { }
int Sync() { return 0; }
bool IsEnabled() { return false; }
bool IsServer() { return false; }
}
// #error Provide a CPUCompare implementation or dummy it out, please
#endif

View File

@ -0,0 +1,50 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Sets up and maintains interprocess communication to make it possible
// to easily compare any two cpu cores by running two instances of DolphinHLE and
// comparing them to each other.
//
#ifndef _CPUCOMPARE_H
#define _CPUCOMPARE_H
#include "Common.h"
namespace CPUCompare
{
// start the server
void StartServer();
// connect as client
void ConnectAsClient();
// stop
void Stop();
// sync
int Sync();
// IsEnabled
bool IsEnabled();
// IsServer
bool IsServer();
void SetBlockStart(u32 addr);
}
#endif

View File

@ -0,0 +1,466 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "../Plugins/Plugin_Video.h"
#include "../PowerPC/PowerPC.h"
#include "../CoreTiming.h"
#include "MathUtil.h"
#include "Thread.h"
#include "Memmap.h"
#include "PeripheralInterface.h"
#include "GPFifo.h"
#include "CPU.h"
#include "../Core.h"
#include "CommandProcessor.h"
namespace CommandProcessor
{
// look for 1002 verts, breakpoint there, see why next draw is flushed
// TODO(ector): Warn on bbox read/write
// Fifo Status Register
union UCPStatusReg
{
struct
{
unsigned OverflowHiWatermark : 1;
unsigned UnderflowLoWatermark : 1;
unsigned ReadIdle : 1;
unsigned CommandIdle : 1;
unsigned Breakpoint : 1;
unsigned : 11;
};
u16 Hex;
UCPStatusReg() {Hex = 0; }
UCPStatusReg(u16 _hex) {Hex = _hex; }
};
// Fifo Control Register
union UCPCtrlReg
{
struct
{
unsigned GPReadEnable : 1;
unsigned CPIntEnable : 1;
unsigned FifoOverflowIntEnable : 1;
unsigned FifoUnderflowIntEnable : 1;
unsigned GPLinkEnable : 1;
unsigned BPEnable : 1;
unsigned : 10;
};
u16 Hex;
UCPCtrlReg() {Hex = 0; }
UCPCtrlReg(u16 _hex) {Hex = _hex; }
};
// Fifo Control Register
union UCPClearReg
{
struct
{
unsigned ClearFifoOverflow : 1;
unsigned ClearFifoUnderflow : 1;
unsigned ClearMetrices : 1;
unsigned : 13;
};
u16 Hex;
UCPClearReg() {Hex = 0; }
UCPClearReg(u16 _hex) {Hex = _hex; }
};
// variables
UCPStatusReg m_CPStatusReg;
UCPCtrlReg m_CPCtrlReg;
UCPClearReg m_CPClearReg;
int m_bboxleft;
int m_bboxtop;
int m_bboxright;
int m_bboxbottom;
u16 m_tokenReg;
CPFifo fifo; //This one is shared between gfx thread and emulator thread
// function
void UpdateFifoRegister();
void UpdateInterrupts();
inline void WriteLow (u32& _reg, u16 lowbits) {_reg = (_reg & 0xFFFF0000) | lowbits;}
inline void WriteHigh(u32& _reg, u16 highbits) {_reg = (_reg & 0x0000FFFF) | ((u32)highbits << 16);}
inline u16 ReadLow (u32 _reg) {return (u16)(_reg & 0xFFFF);}
inline u16 ReadHigh (u32 _reg) {return (u16)(_reg >> 16);}
void Init()
{
m_CPStatusReg.Hex = 0;
m_CPStatusReg.CommandIdle = 1;
m_CPStatusReg.ReadIdle = 1;
m_CPCtrlReg.Hex = 0;
m_bboxleft = 0;
m_bboxtop = 0;
m_bboxright = 640;
m_bboxbottom = 480;
m_tokenReg = 0;
fifo.bFF_GPReadEnable = false;
fifo.bFF_GPLinkEnable = false;
fifo.bFF_BPEnable = false;
#ifdef _WIN32
InitializeCriticalSection(&fifo.sync);
#endif
}
void Shutdown()
{
}
void Read16(u16& _rReturnValue, const u32 _Address)
{
LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address);
if (Core::g_CoreStartupParameter.bUseDualCore)
{
if ((_Address&0xFFF)>=0x20)
{
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance > 0 &&
!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint))
;
fifo.bPauseRead = true;
}
}
switch (_Address & 0xFFF)
{
case STATUS_REGISTER: _rReturnValue = m_CPStatusReg.Hex; return;
case CTRL_REGISTER: _rReturnValue = m_CPCtrlReg.Hex; return;
case CLEAR_REGISTER: _rReturnValue = m_CPClearReg.Hex; return;
case FIFO_TOKEN_REGISTER: _rReturnValue = m_tokenReg; return;
case FIFO_BOUNDING_BOX_LEFT: _rReturnValue = m_bboxleft; return;
case FIFO_BOUNDING_BOX_RIGHT: _rReturnValue = m_bboxright; return;
case FIFO_BOUNDING_BOX_TOP: _rReturnValue = m_bboxtop; return;
case FIFO_BOUNDING_BOX_BOTTOM: _rReturnValue = m_bboxbottom; return;
case FIFO_BASE_LO: _rReturnValue = ReadLow (fifo.CPBase); return;
case FIFO_BASE_HI: _rReturnValue = ReadHigh(fifo.CPBase); return;
case FIFO_END_LO: _rReturnValue = ReadLow (fifo.CPEnd); return;
case FIFO_END_HI: _rReturnValue = ReadHigh(fifo.CPEnd); return;
case FIFO_HI_WATERMARK_LO: _rReturnValue = ReadLow (fifo.CPHiWatermark); return;
case FIFO_HI_WATERMARK_HI: _rReturnValue = ReadHigh(fifo.CPHiWatermark); return;
case FIFO_LO_WATERMARK_LO: _rReturnValue = ReadLow (fifo.CPLoWatermark); return;
case FIFO_LO_WATERMARK_HI: _rReturnValue = ReadHigh(fifo.CPLoWatermark); return;
case FIFO_RW_DISTANCE_LO: _rReturnValue = ReadLow (fifo.CPReadWriteDistance); return;
case FIFO_RW_DISTANCE_HI: _rReturnValue = ReadHigh(fifo.CPReadWriteDistance); return;
case FIFO_WRITE_POINTER_LO: _rReturnValue = ReadLow (fifo.CPWritePointer); return;
case FIFO_WRITE_POINTER_HI: _rReturnValue = ReadHigh(fifo.CPWritePointer); return;
case FIFO_READ_POINTER_LO: _rReturnValue = ReadLow (fifo.CPReadPointer); return;
case FIFO_READ_POINTER_HI: _rReturnValue = ReadHigh(fifo.CPReadPointer); return;
case FIFO_BP_LO: _rReturnValue = ReadLow (fifo.CPBreakpoint); return;
case FIFO_BP_HI: _rReturnValue = ReadHigh(fifo.CPBreakpoint); return;
// case 0x64:
// return 4; //Number of clocks per vertex.. todo: calculate properly
//add all the other regs here? are they ever read?
default:
{
// char szTemp[111];
// sprintf(szTemp, "CCommandProcessor 0x%x", (_Address&0xFFF));
// MessageBox(NULL, szTemp, "mm", MB_OK);
}
_rReturnValue = 0;
return;
}
fifo.bPauseRead = false;
}
bool AllowIdleSkipping()
{
return !Core::g_CoreStartupParameter.bUseDualCore || (!m_CPCtrlReg.CPIntEnable && !m_CPCtrlReg.BPEnable);
}
void Write16(const u16 _Value, const u32 _Address)
{
LOG(COMMANDPROCESSOR, "(w): 0x%04x @ 0x%08x",_Value,_Address);
//Spin until queue is empty - it WILL become empty because this is the only thread
//that submits data
if (Core::g_CoreStartupParameter.bUseDualCore)
{
if ((_Address&0xFFF) >= 0x20)
{
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance > 0 &&
!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint))
;
fifo.bPauseRead = true;
}
}
#ifdef _WIN32
EnterCriticalSection(&fifo.sync);
#endif
switch (_Address & 0xFFF)
{
case STATUS_REGISTER:
{
UCPStatusReg tmpStatus(_Value);
// set the flags to "all is okay"
m_CPStatusReg.OverflowHiWatermark = 0;
m_CPStatusReg.UnderflowLoWatermark = 0;
m_CPStatusReg.ReadIdle = 1;
m_CPStatusReg.CommandIdle = 1;
// breakpoint
if (tmpStatus.Breakpoint)
{
m_CPStatusReg.Breakpoint = 0;
}
fifo.bFF_Breakpoint = m_CPStatusReg.Breakpoint;
// update interrupts
UpdateInterrupts();
LOG(COMMANDPROCESSOR,"write to STATUS_REGISTER : %04x", _Value);
}
break;
case CTRL_REGISTER:
{
m_CPCtrlReg.Hex = _Value;
fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable ? true : false;
fifo.bFF_GPLinkEnable = m_CPCtrlReg.GPLinkEnable ? true : false;
fifo.bFF_BPEnable = m_CPCtrlReg.BPEnable ? true : false;
UpdateInterrupts();
LOG(COMMANDPROCESSOR,"write to CTRL_REGISTER : %04x", _Value);
}
break;
case CLEAR_REGISTER:
{
UCPClearReg tmpClearReg(_Value);
m_CPClearReg.Hex = 0;
LOG(COMMANDPROCESSOR,"write to CLEAR_REGISTER : %04x",_Value);
}
break;
// Fifo Registers
case FIFO_TOKEN_REGISTER: m_tokenReg = _Value; break;
case FIFO_BASE_LO: WriteLow ((u32 &)fifo.CPBase, _Value); fifo.CPBase &= 0xFFFFFFE0; break;
case FIFO_BASE_HI: WriteHigh((u32 &)fifo.CPBase, _Value); fifo.CPBase &= 0xFFFFFFE0; break;
case FIFO_END_LO: WriteLow ((u32 &)fifo.CPEnd, _Value); fifo.CPEnd &= 0xFFFFFFE0; break;
case FIFO_END_HI: WriteHigh((u32 &)fifo.CPEnd, _Value); fifo.CPEnd &= 0xFFFFFFE0; break;
// Hm. Should we really & these with FFFFFFE0?
case FIFO_WRITE_POINTER_LO: WriteLow ((u32 &)fifo.CPWritePointer, _Value); fifo.CPWritePointer &= 0xFFFFFFE0; break;
case FIFO_WRITE_POINTER_HI: WriteHigh((u32 &)fifo.CPWritePointer, _Value); fifo.CPWritePointer &= 0xFFFFFFE0; break;
case FIFO_READ_POINTER_LO: WriteLow ((u32 &)fifo.CPReadPointer, _Value); fifo.CPReadPointer &= 0xFFFFFFE0; break;
case FIFO_READ_POINTER_HI: WriteHigh((u32 &)fifo.CPReadPointer, _Value); fifo.CPReadPointer &= 0xFFFFFFE0; break;
case FIFO_HI_WATERMARK_LO: WriteLow ((u32 &)fifo.CPHiWatermark, _Value); break;
case FIFO_HI_WATERMARK_HI: WriteHigh((u32 &)fifo.CPHiWatermark, _Value); break;
case FIFO_LO_WATERMARK_LO: WriteLow ((u32 &)fifo.CPLoWatermark, _Value); break;
case FIFO_LO_WATERMARK_HI: WriteHigh((u32 &)fifo.CPLoWatermark, _Value); break;
case FIFO_BP_LO: WriteLow ((u32 &)fifo.CPBreakpoint, _Value); break;
case FIFO_BP_HI: WriteHigh((u32 &)fifo.CPBreakpoint, _Value); break;
// ignored writes
case FIFO_RW_DISTANCE_HI:
case FIFO_RW_DISTANCE_LO:
break;
}
// update the registers and run the fifo
// This will recursively enter fifo.sync, TODO(ector): is this good?
UpdateFifoRegister();
#ifdef _WIN32
LeaveCriticalSection(&fifo.sync);
#endif
fifo.bPauseRead = false; // pauseread is not actually used anywhere! TOOD(ector): huh!
}
void Read32(u32& _rReturnValue, const u32 _Address)
{
_rReturnValue = 0;
_dbg_assert_msg_(COMMANDPROCESSOR, 0, "Read32 from CommandProccessor at 0x%08x", _Address);
}
void Write32(const u32 _Data, const u32 _Address)
{
_dbg_assert_msg_(COMMANDPROCESSOR, 0, "Write32 at CommandProccessor at 0x%08x", _Address);
}
void GatherPipeBursted()
{
// we arn't linked, so we don't care about gather pipe data
if (!fifo.bFF_GPLinkEnable)
return;
if (Core::g_CoreStartupParameter.bUseDualCore)
{
// update the fifo-pointer
fifo.CPWritePointer += GPFifo::GATHER_PIPE_SIZE;
if (fifo.CPWritePointer >= fifo.CPEnd)
fifo.CPWritePointer = fifo.CPBase;
// Wait for GPU to catch up
while (!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint) &&
fifo.CPReadWriteDistance > (s32)fifo.CPHiWatermark)
Common::SleepCurrentThread(1);
#ifdef _WIN32
InterlockedExchangeAdd((LONG*)&fifo.CPReadWriteDistance, GPFifo::GATHER_PIPE_SIZE);
#endif
// check if we are in sync
_assert_msg_(COMMANDPROCESSOR, fifo.CPWritePointer == CPeripheralInterface::Fifo_CPUWritePointer, "FIFOs linked but out of sync");
_assert_msg_(COMMANDPROCESSOR, fifo.CPBase == CPeripheralInterface::Fifo_CPUBase, "FIFOs linked but out of sync");
_assert_msg_(COMMANDPROCESSOR, fifo.CPEnd == CPeripheralInterface::Fifo_CPUEnd, "FIFOs linked but out of sync");
if (fifo.bFF_Breakpoint)
{
m_CPStatusReg.Breakpoint = 1;
UpdateInterrupts();
}
}
else
{
fifo.CPWritePointer += GPFifo::GATHER_PIPE_SIZE;
if (fifo.CPWritePointer >= fifo.CPEnd)
fifo.CPWritePointer = fifo.CPBase;
// check if we are in sync
_assert_msg_(COMMANDPROCESSOR, fifo.CPWritePointer == CPeripheralInterface::Fifo_CPUWritePointer, "FIFOs linked but out of sync");
_assert_msg_(COMMANDPROCESSOR, fifo.CPBase == CPeripheralInterface::Fifo_CPUBase, "FIFOs linked but out of sync");
_assert_msg_(COMMANDPROCESSOR, fifo.CPEnd == CPeripheralInterface::Fifo_CPUEnd, "FIFOs linked but out of sync");
UpdateFifoRegister();
}
}
// __________________________________________________________________________________________________
// UpdateFifoRegister
// It's no problem if the gfx falls behind a little bit. Better make sure to stop the cpu thread
// when the distance is way huge, though.
// So:
// CPU thread
/// 0. Write data (done before entering this)
// 1. Compute distance
// 2. If distance > threshold, sleep and goto 1
// GPU thread
// 1. Compute distance
// 2. If distance < threshold, sleep and goto 1 (or wait for trigger?)
// 3. Read and use a bit of data, goto 1
void UpdateFifoRegister()
{
// update the distance
#ifdef _WIN32
if (Core::g_CoreStartupParameter.bUseDualCore) EnterCriticalSection(&fifo.sync);
#endif
int wp = fifo.CPWritePointer;
int rp = fifo.CPReadPointer;
if (wp >= rp)
fifo.CPReadWriteDistance = wp - rp;
else
fifo.CPReadWriteDistance = (wp - fifo.CPBase) +
(fifo.CPEnd - rp);
#ifdef _WIN32
if (Core::g_CoreStartupParameter.bUseDualCore) LeaveCriticalSection(&fifo.sync);
#endif
if (!Core::g_CoreStartupParameter.bUseDualCore)
{
// check if we are able to run this buffer
if ((fifo.bFF_GPReadEnable) && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint))
{
while(fifo.CPReadWriteDistance > 0)
{
// check if we are on a breakpoint
if (fifo.bFF_BPEnable)
{
//MessageBox(0,"Breakpoint enabled",0,0);
if ((fifo.CPReadPointer & ~0x1F) == (fifo.CPBreakpoint & ~0x1F))
{
//_assert_msg_(GEKKO,0,"BP: %08x",fifo.CPBreakpoint);
fifo.bFF_Breakpoint = 1;
m_CPStatusReg.Breakpoint = 1;
//g_VideoInitialize.pUpdateInterrupts();
UpdateInterrupts();
break;
}
}
// read the data and send it to the VideoPlugin
u8 *ptr = Memory::GetPointer(fifo.CPReadPointer);
fifo.CPReadPointer += 32;
// We are going to do FP math on the main thread so have to save the current state
SaveSSEState();
LoadDefaultSSEState();
PluginVideo::Video_SendFifoData(ptr);
LoadSSEState();
fifo.CPReadWriteDistance -= 32;
// increase the ReadPtr
if (fifo.CPReadPointer >= fifo.CPEnd)
{
fifo.CPReadPointer = fifo.CPBase;
LOG(COMMANDPROCESSOR, "BUFFER LOOP");
// MessageBox(NULL, "loop", "now", MB_OK);
}
}
}
}
}
void UpdateInterrupts()
{
if (fifo.bFF_BPEnable && fifo.bFF_Breakpoint)
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_CP, true);
}
else
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_CP, false);
}
}
void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate)
{
UpdateInterrupts();
}
void UpdateInterruptsFromVideoPlugin()
{
CoreTiming::ScheduleEvent_Threadsafe(0, &UpdateInterrupts_Wrapper, "CP:UI");
}
} // end of namespace CommandProcessor

View File

@ -0,0 +1,99 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _COMMANDPROCESSOR_H
#define _COMMANDPROCESSOR_H
#ifdef _WIN32
#include <windows.h>
#endif
extern bool MT;
namespace CommandProcessor
{
// internal hardware addresses
enum
{
STATUS_REGISTER = 0x00,
CTRL_REGISTER = 0x02,
CLEAR_REGISTER = 0x04,
FIFO_TOKEN_REGISTER = 0x0E,
FIFO_BOUNDING_BOX_LEFT = 0x10,
FIFO_BOUNDING_BOX_RIGHT = 0x12,
FIFO_BOUNDING_BOX_TOP = 0x14,
FIFO_BOUNDING_BOX_BOTTOM = 0x16,
FIFO_BASE_LO = 0x20,
FIFO_BASE_HI = 0x22,
FIFO_END_LO = 0x24,
FIFO_END_HI = 0x26,
FIFO_HI_WATERMARK_LO = 0x28,
FIFO_HI_WATERMARK_HI = 0x2a,
FIFO_LO_WATERMARK_LO = 0x2c,
FIFO_LO_WATERMARK_HI = 0x2e,
FIFO_RW_DISTANCE_LO = 0x30,
FIFO_RW_DISTANCE_HI = 0x32,
FIFO_WRITE_POINTER_LO = 0x34,
FIFO_WRITE_POINTER_HI = 0x36,
FIFO_READ_POINTER_LO = 0x38,
FIFO_READ_POINTER_HI = 0x3A,
FIFO_BP_LO = 0x3C,
FIFO_BP_HI = 0x3E
};
struct CPFifo
{
// fifo registers
volatile u32 CPBase;
volatile u32 CPEnd;
u32 CPHiWatermark;
u32 CPLoWatermark;
volatile s32 CPReadWriteDistance;
volatile u32 CPWritePointer;
volatile u32 CPReadPointer;
volatile u32 CPBreakpoint;
volatile bool bFF_GPReadEnable;
volatile bool bFF_BPEnable;
volatile bool bFF_GPLinkEnable;
volatile bool bFF_Breakpoint;
volatile bool bPauseRead;
#ifdef _WIN32
CRITICAL_SECTION sync;
#endif
};
extern CPFifo fifo;
// Init
void Init();
void Shutdown();
// Read
void HWCALL Read16(u16& _rReturnValue, const u32 _Address);
void HWCALL Write16(const u16 _Data, const u32 _Address);
void HWCALL Read32(u32& _rReturnValue, const u32 _Address);
void HWCALL Write32(const u32 _Data, const u32 _Address);
// for CGPFIFO
void GatherPipeBursted();
void UpdateInterrupts();
void UpdateInterruptsFromVideoPlugin();
bool AllowIdleSkipping();
} // end of namespace CommandProcessor
#endif

View File

@ -0,0 +1,557 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "DSP.h"
#include "../CoreTiming.h"
#include "../Core.h"
#include "CPU.h"
#include "MemoryUtil.h"
#include "Memmap.h"
#include "PeripheralInterface.h"
#include "AudioInterface.h"
#include "../PowerPC/PowerPC.h"
#include "../Plugins/Plugin_DSP.h"
namespace DSP
{
// register offsets
enum
{
DSP_MAIL_TO_DSP_HI = 0x5000,
DSP_MAIL_TO_DSP_LO = 0x5002,
DSP_MAIL_FROM_DSP_HI = 0x5004,
DSP_MAIL_FROM_DSP_LO = 0x5006,
DSP_CONTROL = 0x500A,
DSP_INTERRUPT_CONTROL = 0x5010,
AUDIO_DMA_START_HI = 0x5030,
AUDIO_DMA_START_LO = 0x5032,
AUDIO_DMA_CONTROL_LEN = 0x5036,
AUDIO_DMA_BYTES_LEFT = 0x503A,
AR_DMA_MMADDR_H = 0x5020,
AR_DMA_MMADDR_L = 0x5022,
AR_DMA_ARADDR_H = 0x5024,
AR_DMA_ARADDR_L = 0x5026,
AR_DMA_CNT_H = 0x5028,
AR_DMA_CNT_L = 0x502A
};
// aram size and mask
enum
{
ARAM_SIZE = 0x01000000, // 16 MB
ARAM_MASK = 0x00FFFFFF
};
// UARAMCount
union UARAMCount
{
u32 Hex;
struct
{
unsigned count : 31;
unsigned dir : 1;
};
};
// UDSPControl
#define DSP_CONTROL_MASK 0x0C07
union UDSPControl
{
u16 Hex;
struct
{
unsigned DSPReset : 1; // Write 1 to reset and waits for 0
unsigned DSPAssertInt : 1;
unsigned DSPHalt : 1;
unsigned AI : 1;
unsigned AI_mask : 1;
unsigned ARAM : 1;
unsigned ARAM_mask : 1;
unsigned DSP : 1;
unsigned DSP_mask : 1;
unsigned ARAM_DMAState : 1; // DSPGetDMAStatus() uses this flag
unsigned unk3 : 1;
unsigned DSPInit : 1; // DSPInit() writes to this flag (1 as long as dsp PC is in IROM?)
unsigned pad : 4;
};
};
// DSPState
struct DSPState
{
u32 IntControl;
UDSPControl DSPControl;
DSPState()
{
IntControl = 0;
DSPControl.Hex = 0;
}
};
// UDSPControl
union UAudioDMAControl
{
u16 Hex;
struct
{
unsigned NumSamples : 15;
unsigned Enabled : 1;
};
UAudioDMAControl(u16 _Hex = 0) : Hex(_Hex)
{}
};
// AudioDMA
struct AudioDMA
{
u32 SourceAddress;
UAudioDMAControl AudioDMAControl;
u32 SamplesLeft;
};
// ARDMA
struct ARDMA
{
u32 MMAddr;
u32 ARAddr;
UARAMCount Cnt;
bool CntValid[2];
ARDMA()
{
MMAddr = 0;
ARAddr = 0;
Cnt.Hex = 0;
CntValid[0] = false;
CntValid[1] = false;
}
};
u8 *g_ARAM = NULL;
DSPState g_dspState;
AudioDMA g_audioDMA;
ARDMA g_arDMA;
u16 g_AR_READY_FLAG = 0x01;
u16 g_AR_MODE = 0x43; // 0x23 -> Zelda standard mode (standard ARAM access ??)
// 0x43 -> written by OSAudioInit at the UCode upload (upload UCode)
// 0x63 -> ARCheckSize Mode (access AR-registers ??) or no exception ??
void UpdateInterrupts();
void Update_ARAM_DMA();
void WriteARAM(u8 _iValue, u32 _iAddress);
bool Update_DSP_ReadRegister();
void Update_DSP_WriteRegister();
void Init()
{
g_ARAM = (u8 *)AllocateMemoryPages(ARAM_SIZE);
g_dspState.DSPControl.Hex = 0;
g_dspState.DSPControl.DSPHalt = 1;
}
void Shutdown()
{
FreeMemoryPages(g_ARAM, ARAM_SIZE);
g_ARAM = NULL;
}
void Read16(u16& _uReturnValue, const u32 _iAddress)
{
// WTF is this check about? DSP is at 5000 TODO remove
if ((_iAddress & 0x6C00) != 0x6c00)
{
if (_iAddress != 0xCC005004) {
LOG(DSPINTERFACE, "DSPInterface(r16) 0x%08x", _iAddress);
}
switch (_iAddress & 0xFFFF)
{
// ==================================================================================
// AI_REGS 0x5000+
// ==================================================================================
case DSP_MAIL_TO_DSP_HI:
_uReturnValue = PluginDSP::DSP_ReadMailboxHigh(true);
return;
case DSP_MAIL_TO_DSP_LO:
_uReturnValue = PluginDSP::DSP_ReadMailboxLow(true);
return;
case DSP_MAIL_FROM_DSP_HI:
_uReturnValue = PluginDSP::DSP_ReadMailboxHigh(false);
return;
case DSP_MAIL_FROM_DSP_LO:
_uReturnValue = PluginDSP::DSP_ReadMailboxLow(false);
return;
case DSP_CONTROL:
_uReturnValue = (g_dspState.DSPControl.Hex & ~DSP_CONTROL_MASK) |
(PluginDSP::DSP_ReadControlRegister() & DSP_CONTROL_MASK);
return;
// ==================================================================================
// AR_REGS 0x501x+
// ==================================================================================
case 0x5012:
_uReturnValue = g_AR_MODE;
return;
case 0x5016: // ready flag ?
_uReturnValue = g_AR_READY_FLAG;
return;
case 0x501a:
_uReturnValue = 0x000;
return;
case AR_DMA_MMADDR_H: _uReturnValue = g_arDMA.MMAddr>>16; return;
case AR_DMA_MMADDR_L: _uReturnValue = g_arDMA.MMAddr&0xFFFF; return;
case AR_DMA_ARADDR_H: _uReturnValue = g_arDMA.ARAddr>>16; return;
case AR_DMA_ARADDR_L: _uReturnValue = g_arDMA.ARAddr&0xFFFF; return;
case AR_DMA_CNT_H: _uReturnValue = g_arDMA.Cnt.Hex>>16; return;
case AR_DMA_CNT_L: _uReturnValue = g_arDMA.Cnt.Hex&0xFFFF; return;
// ==================================================================================
// DMA_REGS 0x5030+
// ==================================================================================
case AUDIO_DMA_BYTES_LEFT:
_uReturnValue = g_audioDMA.SamplesLeft;
return;
case AUDIO_DMA_START_LO:
_uReturnValue = g_audioDMA.SourceAddress & 0xFFFF;
return;
case AUDIO_DMA_START_HI:
_uReturnValue = g_audioDMA.SourceAddress>>16;
return;
case AUDIO_DMA_CONTROL_LEN:
_uReturnValue = g_audioDMA.AudioDMAControl.Hex;
return;
default:
_dbg_assert_(DSPINTERFACE,0);
break;
}
}
else
{
_dbg_assert_(DSPINTERFACE,0);
}
_uReturnValue = 0x000;
}
void Write16(const u16 _Value, const u32 _Address)
{
LOG(DSPINTERFACE, "DSPInterface(w16) 0x%04x 0x%08x", _Value, _Address);
switch(_Address & 0xFFFF)
{
// ==================================================================================
// DSP Regs 0x5000+
// ==================================================================================
case DSP_MAIL_TO_DSP_HI:
PluginDSP::DSP_WriteMailboxHigh(true, _Value);
break;
case DSP_MAIL_TO_DSP_LO:
PluginDSP::DSP_WriteMailboxLow(true, _Value);
break;
case DSP_MAIL_FROM_DSP_HI:
_dbg_assert_(DSPINTERFACE,0);
break;
case DSP_MAIL_FROM_DSP_LO:
_dbg_assert_(DSPINTERFACE,0);
break;
// ==================================================================================
// Control Register
// ==================================================================================
case DSP_CONTROL:
{
UDSPControl tmpControl;
tmpControl.Hex = (_Value& ~DSP_CONTROL_MASK) |
(PluginDSP::DSP_WriteControlRegister(_Value) & DSP_CONTROL_MASK);
// Update DSP related flags
g_dspState.DSPControl.DSPReset = tmpControl.DSPReset;
g_dspState.DSPControl.DSPAssertInt = tmpControl.DSPAssertInt;
g_dspState.DSPControl.DSPHalt = tmpControl.DSPHalt;
g_dspState.DSPControl.DSPInit = tmpControl.DSPInit;
// Interrupt (mask)
g_dspState.DSPControl.AI_mask = tmpControl.AI_mask;
g_dspState.DSPControl.ARAM_mask = tmpControl.ARAM_mask;
g_dspState.DSPControl.DSP_mask = tmpControl.DSP_mask;
// Interrupt
if (tmpControl.AI) g_dspState.DSPControl.AI = 0;
if (tmpControl.ARAM) g_dspState.DSPControl.ARAM = 0;
if (tmpControl.DSP) g_dspState.DSPControl.DSP = 0;
// g_ARAM
g_dspState.DSPControl.ARAM_DMAState = 0; // keep g_ARAM DMA State zero
// unknown
g_dspState.DSPControl.unk3 = tmpControl.unk3;
g_dspState.DSPControl.pad = tmpControl.pad;
if (g_dspState.DSPControl.pad != 0)
{
LOG(DSPINTERFACE, "DSPInterface(w) g_dspState.DSPControl gets an unknown value");
CCPU::Break();
}
UpdateInterrupts();
}
break;
// ==================================================================================
// AR_REGS 0x501x+
// ==================================================================================
case 0x5012:
g_AR_MODE = _Value;
break;
case 0x5016:
g_AR_READY_FLAG = 0x01; // write what ya want we set 0x01 (rdy flag ??)
break;
case 0x501a:
break;
case AR_DMA_MMADDR_H:
g_arDMA.MMAddr = (g_arDMA.MMAddr & 0xFFFF) | (_Value<<16); break;
case AR_DMA_MMADDR_L:
g_arDMA.MMAddr = (g_arDMA.MMAddr & 0xFFFF0000) | (_Value); break;
case AR_DMA_ARADDR_H:
g_arDMA.ARAddr = (g_arDMA.ARAddr & 0xFFFF) | (_Value<<16); break;
case AR_DMA_ARADDR_L:
g_arDMA.ARAddr = (g_arDMA.ARAddr & 0xFFFF0000) | (_Value); break;
case AR_DMA_CNT_H:
g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF) | (_Value<<16);
g_arDMA.CntValid[0] = true;
Update_ARAM_DMA();
break;
case AR_DMA_CNT_L:
g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF0000) | (_Value);
g_arDMA.CntValid[1] = true;
Update_ARAM_DMA();
break;
// ==================================================================================
// Audio DMA_REGS 0x5030+
// ==================================================================================
case AUDIO_DMA_START_HI:
g_audioDMA.SourceAddress = (g_audioDMA.SourceAddress & 0xFFFF) | (_Value<<16);
break;
case AUDIO_DMA_START_LO:
g_audioDMA.SourceAddress = (g_audioDMA.SourceAddress & 0xFFFF0000) | (_Value);
break;
case AUDIO_DMA_CONTROL_LEN: // called by AIStartDMA()
g_audioDMA.AudioDMAControl.Hex = _Value;
g_audioDMA.SamplesLeft = g_audioDMA.AudioDMAControl.NumSamples;
if (g_audioDMA.AudioDMAControl.Enabled)
{
PluginDSP::DSP_SendAIBuffer(g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumSamples);
g_audioDMA.SamplesLeft = 0;
}
break;
case AUDIO_DMA_BYTES_LEFT:
_dbg_assert_(DSPINTERFACE,0);
break;
default:
_dbg_assert_(DSPINTERFACE,0);
break;
}
}
void Read32(u32& _uReturnValue, const u32 _iAddress)
{
LOG(DSPINTERFACE, "DSPInterface(r) 0x%08x", _iAddress);
switch (_iAddress & 0xFFFF)
{
case DSP_INTERRUPT_CONTROL:
_uReturnValue = g_dspState.IntControl;
return;
default:
_dbg_assert_(DSPINTERFACE,0);
break;
}
_uReturnValue = 0;
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
LOG(DSPINTERFACE, "DSPInterface(w) 0x%08x 0x%08x", _iValue, _iAddress);
switch (_iAddress & 0xFFFF)
{
// ==================================================================================
// AR_REGS - i dont know why they are accessed 32 bit too ...
// ==================================================================================
case AR_DMA_MMADDR_H:
g_arDMA.MMAddr = _iValue;
break;
case AR_DMA_ARADDR_H:
g_arDMA.ARAddr = _iValue;
break;
case AR_DMA_CNT_H:
g_arDMA.Cnt.Hex = _iValue;
g_arDMA.CntValid[0] = g_arDMA.CntValid[1] = true;
Update_ARAM_DMA();
break;
default:
_dbg_assert_(DSPINTERFACE,0);
break;
}
}
// __________________________________________________________________________________________________
// UpdateInterrupts
//
void UpdateInterrupts()
{
if ((g_dspState.DSPControl.AI & g_dspState.DSPControl.AI_mask) ||
(g_dspState.DSPControl.ARAM & g_dspState.DSPControl.ARAM_mask) ||
(g_dspState.DSPControl.DSP & g_dspState.DSPControl.DSP_mask))
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_DSP, true);
}
else
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_DSP, false);
}
}
void GenerateDSPInterrupt(DSPInterruptType type, bool _bSet)
{
switch (type)
{
case INT_DSP: g_dspState.DSPControl.DSP = _bSet ? 1 : 0; break;
case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; break;
case INT_AI: g_dspState.DSPControl.AI = _bSet ? 1 : 0; break;
}
UpdateInterrupts();
}
void GenerateDSPInterrupt_Wrapper(u64 userdata, int cyclesLate)
{
GenerateDSPInterrupt((DSPInterruptType)(userdata&0xFFFF), (bool)((userdata>>16) & 1));
}
// CALLED FROM DSP PLUGIN, POSSIBLY THREADED
void GenerateDSPInterruptFromPlugin(DSPInterruptType type, bool _bSet)
{
CoreTiming::ScheduleEvent_Threadsafe(
0, GenerateDSPInterrupt_Wrapper, "DSPInt", type | (_bSet<<16));
}
void Update_ARAM_DMA()
{
// check if the count reg is valid
if (!g_arDMA.CntValid[0] || !g_arDMA.CntValid[1])
return;
g_arDMA.CntValid[0] = g_arDMA.CntValid[1] = false;
LOG(DSPINTERFACE,"ARAM DMA triggered");
//TODO: speedup
if (g_arDMA.Cnt.dir)
{
//read from ARAM
LOG(DSPINTERFACE,"ARAM DMA read %08x bytes from %08x to Mem: %08x",g_arDMA.Cnt.count, g_arDMA.ARAddr, g_arDMA.MMAddr);
u32 iMemAddress = g_arDMA.MMAddr;
u32 iARAMAddress = g_arDMA.ARAddr;
// TODO(??): sanity check instead of writing bogus data?
for (u32 i=0; i<g_arDMA.Cnt.count; i++)
{
u32 tmp = (iARAMAddress < ARAM_SIZE) ? g_ARAM[iARAMAddress] : 0x05050505;
Memory::Write_U8(tmp, iMemAddress);
iMemAddress++;
iARAMAddress++;
}
}
else
{
u32 iMemAddress = g_arDMA.MMAddr;
u32 iARAMAddress = g_arDMA.ARAddr;
//write to g_ARAM
LOG(DSPINTERFACE,"g_ARAM DMA write %08x bytes from %08x to Aram: %08x",g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr);
for (u32 i=0; i<g_arDMA.Cnt.count; i++)
{
if (iARAMAddress < ARAM_SIZE)
g_ARAM[iARAMAddress] = Memory::Read_U8(iMemAddress);
iMemAddress++;
iARAMAddress++;
}
}
g_arDMA.Cnt.count = 0;
GenerateDSPInterrupt(INT_ARAM);
}
u8 ReadARAM(const u32 _iAddress)
{
// _dbg_assert_(DSPINTERFACE,(_iAddress) < ARAM_SIZE);
return g_ARAM[_iAddress & ARAM_MASK];
}
u8* GetARAMPtr()
{
return g_ARAM;
}
void WriteARAM(u8 _iValue, u32 _iAddress)
{
// _dbg_assert_(DSPINTERFACE,(_iAddress) < ARAM_SIZE);
//rouge leader writes WAY outside
//not really surprising since it uses a totally different memory model :P
g_ARAM[_iAddress & ARAM_MASK] = _iValue;
}
} // end of namespace DSP

View File

@ -0,0 +1,58 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DSPINTERFACE_H
#define _DSPINTERFACE_H
#include "Common.h"
namespace DSP
{
enum DSPInterruptType
{
INT_DSP = 0,
INT_ARAM = 1,
INT_AI = 2
};
void Init();
void Shutdown();
void GenerateDSPInterrupt(DSPInterruptType _DSPInterruptType, bool _bSet = true);
void GenerateDSPInterruptFromPlugin(DSPInterruptType _DSPInterruptType, bool _bSet = true);
// Read32
void HWCALL Read16(u16& _uReturnValue, const u32 _uAddress);
void HWCALL Read32(u32& _uReturnValue, const u32 _uAddress);
// Write
void HWCALL Write16(const u16 _uValue, const u32 _uAddress);
void HWCALL Write32(const u32 _uValue, const u32 _uAddress);
// Audio/DSP Plugin Helper
u8 ReadARAM(const u32 _uAddress);
// Debugger Helper
u8* GetARAMPtr();
void UpdateAudioDMA();
}// end of namespace DSP
#endif

View File

@ -0,0 +1,574 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "StreamADPCM.H"
#include "DVDInterface.h"
#include "../PowerPC/PowerPC.h"
#include "PeripheralInterface.h"
#include "Memmap.h"
#include "../VolumeHandler.h"
namespace DVDInterface
{
/*
20975: 00000000 DVD (zzz_80146b84 ??, 0x80146bf8) : DVD(r): 0xcc006004
20976: 00000000 DVD (zzz_80146b84 ??, 0x80146c00) : DVD(w): 0x00000000 @ 0xcc006004
20977: 00000000 DVD (DVDLowRead, 0x801448a8) : DVD(w): 0x00000020 @ 0xcc006018
20978: 00000000 DVD (Read, 0x80144744) : DVD(w): 0xa8000000 @ 0xcc006008
20979: 00000000 DVD (Read, 0x80144750) : DVD(w): 0x01094227 @ 0xcc00600c
20980: 00000000 DVD (Read, 0x80144758) : DVD(w): 0x00000020 @ 0xcc006010
20981: 00000000 DVD (Read, 0x8014475c) : DVD(w): 0x8167cc80 @ 0xcc006014
20982: 00000000 DVD (Read, 0x80144760) : DVD(w): 0x00000020 @ 0xcc006018
20983: 00000000 DVD (Read, 0x80144768) : DVD(w): 0x00000003 @ 0xcc00601c
20984: 00000000 DVD: DVD: Read ISO: DVDOffset=0425089c, DMABuffer=0167cc80, SrcLength=00000020, DMALength=00000020
20989: 00000000 DVD (zzz_801442fc ??, 0x80144388) : DVD(r): 0xcc006000
20990: 00000000 DVD (zzz_801442fc ??, 0x801443d8) : DVD(w): 0x0000003a @ 0xcc006000
20992: 00000000 DVD (zzz_801442fc ??, 0x801444d0) : DVD(w): 0x00000000 @ 0xcc006004
20993: 00000000 DVD (zzz_80146e44 ??, 0x80146fcc) : DVD(r): 0xcc006018
After this, Cubivore infinitely calls DVDGetDriveStatus, which does not even
bother to check any DVD regs
*/
// internal hardware addresses
enum
{
DI_STATUS_REGISTER = 0x00,
DI_COVER_REGISTER = 0x04,
DI_COMMAND_0 = 0x08,
DI_COMMAND_1 = 0x0C,
DI_COMMAND_2 = 0x10,
DI_DMA_ADDRESS_REGISTER = 0x14,
DI_DMA_LENGTH_REGISTER = 0x18,
DI_DMA_CONTROL_REGISTER = 0x1C,
DI_IMMEDIATE_DATA_BUFFER = 0x20,
DI_CONFIG_REGISTER = 0x24
};
// DVD IntteruptTypes
enum DVDInterruptType
{
INT_DEINT = 0,
INT_TCINT = 1,
INT_BRKINT = 2,
INT_CVRINT
};
// DI Status Register
union UDISR
{
u32 Hex;
struct
{
unsigned BREAK : 1; // Stop the Device + Interrupt
unsigned DEINITMASK : 1; // Access Device Error Int Mask
unsigned DEINT : 1; // Access Device Error Int
unsigned TCINTMASK : 1; // Transfer Complete Int Mask
unsigned TCINT : 1; // Transfer Complete Int
unsigned BRKINTMASK : 1;
unsigned BRKINT : 1; // w 1: clear brkint
unsigned : 25;
};
UDISR() {Hex = 0;}
UDISR(u32 _hex) {Hex = _hex;}
};
// DI Cover Register
union UDICVR
{
u32 Hex;
struct
{
unsigned CVR : 1; // 0: Cover closed 1: Cover open
unsigned CVRINTMASK : 1; // 1: Interrupt enabled;
unsigned CVRINT : 1; // 1: Interrupt clear
unsigned : 29;
};
UDICVR() {Hex = 0;}
UDICVR(u32 _hex) {Hex = _hex;}
};
// DI DMA Address Register
union UDIDMAAddressRegister
{
u32 Hex;
struct
{
unsigned Address : 26;
unsigned : 6;
};
};
// DI DMA Address Length Register
union UDIDMAAddressLength
{
u32 Hex;
struct
{
unsigned Length : 26;
unsigned : 6;
};
};
// DI DMA Control Register
union UDIDMAControlRegister
{
u32 Hex;
struct
{
unsigned TSTART : 1; // w:1 start r:0 ready
unsigned DMA : 1; // 1: DMA Mode 0: Immediate Mode (can only do Access Register Command)
unsigned RW : 1; // 0: Read Command (DVD to Memory) 1: Write COmmand (Memory to DVD)
unsigned : 29;
};
};
// DI Config Register
union UDIConfigRegister
{
u32 Hex;
struct
{
unsigned CONFIG : 8;
unsigned : 24;
};
UDIConfigRegister() {Hex = 0;}
UDIConfigRegister(u32 _hex) {Hex = _hex;}
};
// hardware registers
struct DVDMemStruct
{
UDISR StatusReg;
UDICVR CoverReg;
u32 Command[3];
UDIDMAAddressRegister DMAAddress;
UDIDMAAddressLength DMALength;
UDIDMAControlRegister DMAControlReg;
u32 Immediate;
UDIConfigRegister ConfigReg;
u32 AudioStart;
u32 AudioPos;
u32 AudioLength;
};
DVDMemStruct dvdMem;
// helper
u32 g_ErrorCode = 0x00;
bool g_bDiscInside = true;
void UpdateInterrupts();
void GenerateDVDInterrupt(DVDInterruptType _DVDInterrupt);
void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg);
void Init()
{
dvdMem.StatusReg.Hex = 0;
dvdMem.CoverReg.Hex = 0;
dvdMem.Command[0] = 0;
dvdMem.Command[1] = 0;
dvdMem.Command[2] = 0;
dvdMem.DMAAddress.Hex = 0;
dvdMem.DMALength.Hex = 0;
dvdMem.DMAControlReg.Hex = 0;
dvdMem.Immediate = 0;
dvdMem.ConfigReg.Hex = 0;
dvdMem.AudioStart = 0;
dvdMem.AudioPos = 0;
dvdMem.AudioLength = 0;
// SetLidOpen(true);
}
void Shutdown()
{
}
void SetDiscInside(bool _DiscInside)
{
g_bDiscInside = _DiscInside;
}
void SetLidOpen(bool _bOpen)
{
if (_bOpen)
dvdMem.CoverReg.CVR = 1;
else
dvdMem.CoverReg.CVR = 0;
UpdateInterrupts();
}
bool IsLidOpen()
{
if (dvdMem.CoverReg.CVR)
return true;
else
return false;
}
bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength)
{
return VolumeHandler::ReadToPtr(Memory::GetPointer(_iRamAddress), _iDVDOffset, _iLength);
}
bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples)
{
if (dvdMem.AudioPos == 0)
{
//MessageBox(0,"DVD: Trying to stream from 0", "bah", 0);
memset(_pDestBuffer, 0, _iNumSamples); // probably __AI_SRC_INIT :P
return false;
}
_iNumSamples &= ~31;
VolumeHandler::ReadToPtr(_pDestBuffer, dvdMem.AudioPos, _iNumSamples);
//
// FIX THIS
//
// loop check
//
dvdMem.AudioPos += _iNumSamples;
if (dvdMem.AudioPos >= dvdMem.AudioStart + dvdMem.AudioLength)
{
dvdMem.AudioPos = dvdMem.AudioStart;
NGCADPCM::InitFilter();
}
//LOG(DVDINTERFACE,"ReadADPCM");
return true;
}
void Read32(u32& _uReturnValue, const u32 _iAddress)
{
LOG(DVDINTERFACE, "DVD(r): 0x%08x", _iAddress);
switch (_iAddress & 0xFFF)
{
case DI_STATUS_REGISTER: _uReturnValue = dvdMem.StatusReg.Hex; return;
case DI_COVER_REGISTER: _uReturnValue = dvdMem.CoverReg.Hex; return;
case DI_COMMAND_0: _uReturnValue = dvdMem.Command[0]; return;
case DI_COMMAND_1: _uReturnValue = dvdMem.Command[1]; return;
case DI_COMMAND_2: _uReturnValue = dvdMem.Command[2]; return;
case DI_DMA_ADDRESS_REGISTER: _uReturnValue = dvdMem.DMAAddress.Hex; return;
case DI_DMA_LENGTH_REGISTER: _uReturnValue = dvdMem.DMALength.Hex; return;
case DI_DMA_CONTROL_REGISTER: _uReturnValue = dvdMem.DMAControlReg.Hex; return;
case DI_IMMEDIATE_DATA_BUFFER: _uReturnValue = dvdMem.Immediate; return;
case DI_CONFIG_REGISTER:
{
dvdMem.ConfigReg.Hex = 0x000000FF;
_uReturnValue = dvdMem.ConfigReg.Hex;
return;
}
default:
_dbg_assert_(DVDINTERFACE,0);
}
_uReturnValue = 0;
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
LOG(DVDINTERFACE, "DVD(w): 0x%08x @ 0x%08x", _iValue, _iAddress);
switch (_iAddress & 0x3FF)
{
case DI_STATUS_REGISTER:
{
UDISR tmpStatusReg(_iValue);
dvdMem.StatusReg.DEINITMASK = tmpStatusReg.DEINITMASK;
dvdMem.StatusReg.TCINTMASK = tmpStatusReg.TCINTMASK;
dvdMem.StatusReg.BRKINTMASK = tmpStatusReg.BRKINTMASK;
if (tmpStatusReg.DEINT) dvdMem.StatusReg.DEINT = 0;
if (tmpStatusReg.TCINT) dvdMem.StatusReg.TCINT = 0;
if (tmpStatusReg.BRKINT) dvdMem.StatusReg.BRKINT = 0;
if (tmpStatusReg.BREAK)
{
_dbg_assert_(DVDINTERFACE, 0);
}
UpdateInterrupts();
}
break;
case DI_COVER_REGISTER:
{
UDICVR tmpCoverReg(_iValue);
dvdMem.CoverReg.CVR = 0;
dvdMem.CoverReg.CVRINTMASK = tmpCoverReg.CVRINTMASK;
if (tmpCoverReg.CVRINT) dvdMem.CoverReg.CVRINT = 0;
UpdateInterrupts();
_dbg_assert_(DVDINTERFACE, (tmpCoverReg.CVR == 0));
}
break;
case DI_COMMAND_0: dvdMem.Command[0] = _iValue; break;
case DI_COMMAND_1: dvdMem.Command[1] = _iValue; break;
case DI_COMMAND_2: dvdMem.Command[2] = _iValue; break;
case DI_DMA_ADDRESS_REGISTER:
{
dvdMem.DMAAddress.Hex = _iValue;
_dbg_assert_(DVDINTERFACE, ((dvdMem.DMAAddress.Hex & 0x1F) == 0));
}
break;
case DI_DMA_LENGTH_REGISTER: dvdMem.DMALength.Hex = _iValue; break;
case DI_DMA_CONTROL_REGISTER:
{
dvdMem.DMAControlReg.Hex = _iValue;
if (dvdMem.DMAControlReg.TSTART)
{
ExecuteCommand(dvdMem.DMAControlReg);
}
}
break;
case DI_IMMEDIATE_DATA_BUFFER: dvdMem.Immediate = _iValue; break;
case DI_CONFIG_REGISTER:
{
UDIConfigRegister tmpConfigReg(_iValue);
dvdMem.ConfigReg.CONFIG = tmpConfigReg.CONFIG;
}
break;
default:
_dbg_assert_msg_(DVDINTERFACE, 0, "Write to unknown DI address 0x%08x", _iAddress);
break;
}
}
void UpdateInterrupts()
{
if ((dvdMem.StatusReg.DEINT & dvdMem.StatusReg.DEINITMASK) ||
(dvdMem.StatusReg.TCINT & dvdMem.StatusReg.TCINTMASK) ||
(dvdMem.StatusReg.BRKINT & dvdMem.StatusReg.BRKINTMASK) ||
(dvdMem.CoverReg.CVRINT & dvdMem.CoverReg.CVRINTMASK))
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_DI, true);
}
else
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_DI, false);
}
}
void GenerateDVDInterrupt(DVDInterruptType _DVDInterrupt)
{
switch(_DVDInterrupt)
{
case INT_DEINT: dvdMem.StatusReg.DEINT = 1; break;
case INT_TCINT: dvdMem.StatusReg.TCINT = 1; break;
case INT_BRKINT: dvdMem.StatusReg.BRKINT = 1; break;
case INT_CVRINT: dvdMem.CoverReg.CVRINT = 1; break;
}
UpdateInterrupts();
}
bool m_bStream = false;
void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg)
{
_dbg_assert_(DVDINTERFACE, _DMAControlReg.RW == 0); // only DVD to Memory
switch ((dvdMem.Command[0] & 0xFF000000) >> 24)
{
//=========================================================================================================
// DRIVE INFO (DMA)
// Command/Subcommand/Padding <- 12000000
// Command0 <- 0
// Command1 <- 0x20
// Command2 <- Address in ram of the buffer
//
// output buffer:
// 0000-0001 revisionLevel
// 0002-0003 deviceCode
// 0004-0007 releaseDate
// 0008-001F padding(0)
//=========================================================================================================
case 0x12:
{
u32 offset = dvdMem.Command[1];
// u32 sourcelength = dvdMem.Command[2];
u32 destbuffer = dvdMem.DMAAddress.Address;
u32 destlength = dvdMem.DMALength.Length;
dvdMem.DMALength.Length = 0;
LOG(DVDINTERFACE, "[WARNING] DVD: Get drive info offset=%08x, destbuffer=%08x, destlength=%08x", offset * 4, destbuffer, destlength);
// metroid uses this...
for (unsigned int i = 0; i < destlength / 4; i++)
{
Memory::Write_U32(0, destbuffer + i * 4);
}
}
break;
//=========================================================================================================
// READ (DMA)
// Command/Subcommand/Padding <- A8000000
// Command0 <- Position on DVD shr 2
// Command1 <- Length of the read
// Command2 <- Address in ram of the buffer
//=========================================================================================================
case 0xA8:
{
if (g_bDiscInside)
{
u32 iDVDOffset = dvdMem.Command[1] << 2;
u32 iSrcLength = dvdMem.Command[2];
LOG(DVDINTERFACE, "DVD: Read ISO: DVDOffset=%08x, DMABuffer=%08x, SrcLength=%08x, DMALength=%08x",iDVDOffset,dvdMem.DMAAddress.Address,iSrcLength,dvdMem.DMALength.Length);
_dbg_assert_(DVDINTERFACE, iSrcLength == dvdMem.DMALength.Length);
if (VolumeHandler::ReadToPtr(Memory::GetPointer(dvdMem.DMAAddress.Address), iDVDOffset, dvdMem.DMALength.Length) != true)
{
PanicAlert("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
}
}
else
{
// there is no disc to read
GenerateDVDInterrupt(INT_DEINT);
g_ErrorCode = 0x03023A00;
return;
}
}
break;
//=========================================================================================================
// SEEK (Immediate)
// Command/Subcommand/Padding <- AB000000
// Command0 <- Position on DVD shr 2
//=========================================================================================================
case 0xAB:
{
u32 offset = dvdMem.Command[1] << 2;
LOG(DVDINTERFACE, "DVD: Trying to seek: offset=%08x", offset);
}
break;
//=========================================================================================================
// REQUEST ERROR (Immediate)
// Command/Subcommand/Padding <- E0000000
//=========================================================================================================
case 0xE0:
LOG(DVDINTERFACE, "DVD: Requesting error");
dvdMem.Immediate = g_ErrorCode;
break;
//=========================================================================================================
// AUDIOSTREAM (Immediate)
// Command/Subcommand/Padding <- E1??0000 ?? = subcommand
// Command0 <- Position on DVD shr 2
// Command1 <- Length of the stream
//=========================================================================================================
case 0xE1:
{
// i dunno if we need this check
// if (m_bStream)
// MessageBox(NULL, "dont overwrite a stream while you play it", "FATAL ERROR", MB_OK);
// subcommand
// ugly hack to catch the disable command
if (dvdMem.Command[1]!=0)
{
u8 subCommand = (dvdMem.Command[0] & 0x00FF0000) >> 16;
dvdMem.AudioPos = dvdMem.Command[1] << 2;
dvdMem.AudioStart = dvdMem.AudioPos;
dvdMem.AudioLength = dvdMem.Command[2];
NGCADPCM::InitFilter();
m_bStream = true;
LOG(DVDINTERFACE, "DVD(Audio) Stream subcmd = %02x offset = %08x length=%08x", subCommand, dvdMem.AudioPos, dvdMem.AudioLength);
}
}
break;
//=========================================================================================================
// REQUEST AUDIO STATUS (Immediate)
// Command/Subcommand/Padding <- E2000000
//=========================================================================================================
case 0xE2:
{
/* if (m_bStream)
dvdMem.Immediate = 1;
else
dvdMem.Immediate = 0;*/
}
LOG(DVDINTERFACE, "DVD(Audio): Request Audio status");
break;
//=========================================================================================================
// STOP MOTOR (Immediate)
// Command/Subcommand/Padding <- E3000000
//=========================================================================================================
case 0xE3:
LOG(DVDINTERFACE, "DVD: Stop motor");
break;
//=========================================================================================================
// DVD AUDIO DISABLE (Immediate)`
// Command/Subcommand/Padding <- E4000000 (disable)
// Command/Subcommand/Padding <- E4010000 (enable)
//=========================================================================================================
case 0xE4:
/* if (((dvdMem.Command[0] & 0x00FF0000) >> 16) == 1)
{
m_bStream = true;
LOG(DVDINTERFACE, "DVD(Audio): Audio enabled");
}
else
{
m_bStream = false;
LOG(DVDINTERFACE, "DVD(Audio): Audio disabled");
}*/
break;
//=========================================================================================================
// UNKNOWN DVD COMMAND
//=========================================================================================================
default:
PanicAlert("DVD - Unknown DVD command %08x - fatal error", dvdMem.Command[0]);
_dbg_assert_(DVDINTERFACE, 0);
break;
}
// transfer is done
_DMAControlReg.TSTART = 0;
dvdMem.DMALength.Length = 0;
GenerateDVDInterrupt(INT_TCINT);
g_ErrorCode = 0x00;
}
} // namespace

View File

@ -0,0 +1,49 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DVDINTERFACE_H
#define _DVDINTERFACE_H
#include "Common.h"
namespace DVDInterface
{
// Init
void Init();
void Shutdown();
void SetDiscInside(bool _DiscInside);
// Lid Functions
void SetLidOpen(bool open);
bool IsLidOpen();
// DVD Access Functions
bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength);
bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples);
// Read32
void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
// Write32
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
} // end of namespace DVDInterface
#endif

View File

@ -0,0 +1,104 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "PeripheralInterface.h"
#include "../PowerPC/PowerPC.h"
#include "EXI_Device.h"
#include "EXI_Channel.h"
namespace ExpansionInterface
{
enum
{
NUM_CHANNELS = 3
};
CEXIChannel *g_Channels;
void Init()
{
g_Channels = new CEXIChannel[3];
g_Channels[0].m_ChannelId = 0;
g_Channels[1].m_ChannelId = 1;
g_Channels[2].m_ChannelId = 2;
g_Channels[0].AddDevice(EXIDEVICE_MEMORYCARD_A, 0);
g_Channels[0].AddDevice(EXIDEVICE_IPL, 1);
g_Channels[1].AddDevice(EXIDEVICE_MEMORYCARD_B, 0);
g_Channels[2].AddDevice(EXIDEVICE_AD16, 0);
}
void Shutdown()
{
delete [] g_Channels;
g_Channels = 0;
}
void Update()
{
g_Channels[0].Update();
g_Channels[1].Update();
g_Channels[2].Update();
}
void Read32(u32& _uReturnValue, const u32 _iAddress)
{
unsigned int iAddr = _iAddress & 0x3FF;
unsigned int iRegister = (iAddr >> 2) % 5;
unsigned int iChannel = (iAddr >> 2) / 5;
_dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS);
if (iChannel < NUM_CHANNELS)
{
g_Channels[iChannel].Read32(_uReturnValue, iRegister);
}
else
{
_uReturnValue = 0;
}
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
int iAddr = _iAddress & 0x3FF;
int iRegister = (iAddr >> 2) % 5;
int iChannel = (iAddr >> 2) / 5;
_dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS)
if (iChannel < NUM_CHANNELS)
g_Channels[iChannel].Write32(_iValue, iRegister);
}
void UpdateInterrupts()
{
for(int i=0; i<NUM_CHANNELS; i++)
{
if(g_Channels[i].isCausingInterrupt())
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_EXI, true);
return;
}
}
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_EXI, false);
}
} // end of namespace ExpansionInterface

View File

@ -0,0 +1,43 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EXIINTERFACE_H
#define _EXIINTERFACE_H
#include "Common.h"
namespace ExpansionInterface
{
// init
void Init();
// shutdown
void Shutdown();
// update
void Update();
// updateInterrupts
void UpdateInterrupts();
void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
} // end of namespace ExpansionInterface
#endif

View File

@ -0,0 +1,278 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "EXI_Channel.h"
#include "EXI.h"
#include "PeripheralInterface.h"
#include "../PowerPC/PowerPC.h"
CEXIChannel::CEXIChannel() :
m_DMAMemoryAddress(0),
m_DMALength(0),
m_ImmData(0),
m_ChannelId(-1)
{
m_Control.hex = 0;
m_Status.hex = 0;
m_Status.CHIP_SELECT = 1;
for (int i=0; i<NUM_DEVICES; i++)
{
m_pDevices[i] = EXIDevice_Create(EXIDEVICE_DUMMY);
_dbg_assert_(EXPANSIONINTERFACE, m_pDevices[i] != NULL);
}
m_Status.TCINTMASK = 1;
}
CEXIChannel::~CEXIChannel()
{
RemoveDevices();
}
void CEXIChannel::RemoveDevices()
{
for (int i=0; i<NUM_DEVICES; i++)
{
if (m_pDevices[i] != NULL)
{
delete m_pDevices[i];
m_pDevices[i] = NULL;
}
}
}
void CEXIChannel::AddDevice(const TEXIDevices _device, const unsigned int _iSlot)
{
_dbg_assert_(EXPANSIONINTERFACE, _iSlot < NUM_DEVICES);
// delete the old device
if (m_pDevices[_iSlot] != NULL)
{
delete m_pDevices[_iSlot];
m_pDevices[_iSlot] = NULL;
}
// create the new one
m_pDevices[_iSlot] = EXIDevice_Create(_device);
_dbg_assert_(EXPANSIONINTERFACE, m_pDevices[_iSlot] != NULL);
}
void CEXIChannel::UpdateInterrupts()
{
ExpansionInterface::UpdateInterrupts();
}
bool CEXIChannel::isCausingInterrupt()
{
if (m_ChannelId != 2) /* Channels 0 and 1: Memcard slot (device 0) produces interrupt */
{
if(m_pDevices[0]->IsInterruptSet())
m_Status.EXIINT = 1;
} else /* Channel 2: In fact, Channel 0, Device 2 (Serial A) produces interrupt */
{
if (this[-2].m_pDevices[2]->IsInterruptSet())
m_Status.EXIINT = 1;
}
if ((m_Status.EXIINT & m_Status.EXIINTMASK) ||
(m_Status.TCINT & m_Status.TCINTMASK) ||
(m_Status.EXTINT & m_Status.EXTINTMASK))
{
return true;
}
else
{
return false;
}
}
IEXIDevice* CEXIChannel::GetDevice(u8 _CHIP_SELECT)
{
switch(_CHIP_SELECT)
{
case 1: return m_pDevices[0];
case 2: return m_pDevices[1];
case 4: return m_pDevices[2];
}
return NULL;
}
void CEXIChannel::Update()
{
// start the transfer
for(int i=0; i<NUM_DEVICES; i++)
{
m_pDevices[i]->Update();
}
}
void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
{
LOG(EXPANSIONINTERFACE, "ExtensionInterface(R): channel: %i reg: %i", m_ChannelId, _iRegister);
switch (_iRegister)
{
case EXI_STATUS:
{
// check if a device is present
for(int i=0; i<NUM_DEVICES; i++)
{
if(m_pDevices[i]->IsPresent())
{
m_Status.EXT = 1;
break;
}
}
_uReturnValue = m_Status.hex;
return;
}
case EXI_DMAADDR:
_uReturnValue = m_DMAMemoryAddress;
return;
case EXI_DMALENGTH:
_uReturnValue = m_DMALength;
return;
case EXI_DMACONTROL:
_uReturnValue = m_Control.hex;
return;
case EXI_IMMDATA:
_uReturnValue = m_ImmData;
return;
}
_dbg_assert_(EXPANSIONINTERFACE, 0);
_uReturnValue = 0xDEADBEEF;
}
void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
{
LOG(EXPANSIONINTERFACE, "ExtensionInterface(W): 0x%08x channel: %i reg: %i", _iValue, m_ChannelId, _iRegister);
switch (_iRegister)
{
case EXI_STATUS:
{
UEXI_STATUS newStatus(_iValue);
// static
m_Status.EXIINTMASK = newStatus.EXIINTMASK;
m_Status.TCINTMASK = newStatus.TCINTMASK;
m_Status.EXTINTMASK = newStatus.EXTINTMASK;
m_Status.CLK = newStatus.CLK;
m_Status.ROMDIS = newStatus.ROMDIS;
// Device
if (m_Status.CHIP_SELECT != newStatus.CHIP_SELECT)
{
for (int i=0; i<NUM_DEVICES; i++)
{
u8 dwDeviceMask = 1 << i;
IEXIDevice* pDevice = GetDevice(dwDeviceMask);
if (pDevice != NULL)
{
if (((newStatus.CHIP_SELECT & dwDeviceMask) == dwDeviceMask) &&
((m_Status.CHIP_SELECT & dwDeviceMask) == 0))
// device gets activated
pDevice->SetCS(1);
if (((newStatus.CHIP_SELECT & dwDeviceMask) == 0) &&
((m_Status.CHIP_SELECT & dwDeviceMask) == dwDeviceMask))
// device gets deactivated
pDevice->SetCS(0);
}
}
m_Status.CHIP_SELECT = newStatus.CHIP_SELECT;
}
// External Status
IEXIDevice* pDevice = GetDevice(newStatus.CHIP_SELECT);
if (pDevice != NULL)
m_Status.EXT = pDevice->IsPresent() ? 1 : 0;
else
m_Status.EXT = 0;
// interrupt
if (newStatus.EXIINT) m_Status.EXIINT = 0;
if (newStatus.TCINT) m_Status.TCINT = 0;
if (newStatus.EXTINT) m_Status.EXTINT = 0;
UpdateInterrupts();
}
break;
case EXI_DMAADDR:
LOG(EXPANSIONINTERFACE, "EXI: Wrote DMABuf, chan %i", m_ChannelId);
m_DMAMemoryAddress = _iValue;
break;
case EXI_DMALENGTH:
LOG(EXPANSIONINTERFACE, "EXI: Wrote DMASize, chan %i", m_ChannelId);
m_DMALength = _iValue;
break;
case EXI_DMACONTROL:
LOG(EXPANSIONINTERFACE, "EXI: Wrote DMAControl, chan %i", m_ChannelId);
m_Control.hex = _iValue;
if (m_Control.TSTART)
{
IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT);
if (pDevice == NULL)
return;
if (m_Control.DMA == 0)
{
// immediate data
switch (m_Control.RW)
{
case 0: m_ImmData = pDevice->ImmRead(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);
}
m_Control.TSTART = 0;
}
else
{
// DMA
switch (m_Control.RW)
{
case 0: pDevice->DMARead (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);
}
m_Control.TSTART = 0;
}
if(!m_Control.TSTART) // completed !
{
m_Status.TCINT = 1;
UpdateInterrupts();
}
}
break;
case EXI_IMMDATA:
LOG(EXPANSIONINTERFACE, "EXI: Wrote IMMData, chan %i", m_ChannelId);
m_ImmData = _iValue;
break;
}
}

View File

@ -0,0 +1,124 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EXICHANNEL_H
#define _EXICHANNEL_H
#include "Common.h"
#include "EXI_Device.h"
class CEXIChannel
{
private:
enum
{
EXI_STATUS = 0,
EXI_DMAADDR = 1,
EXI_DMALENGTH = 2,
EXI_DMACONTROL = 3,
EXI_IMMDATA = 4
};
// EXI Status Register
union UEXI_STATUS
{
u32 hex;
struct
{
unsigned EXIINTMASK : 1; // 31
unsigned EXIINT : 1; //30
unsigned TCINTMASK : 1; //29
unsigned TCINT : 1; //28
unsigned CLK : 3; //27
unsigned CHIP_SELECT : 3; //24
unsigned EXTINTMASK : 1; //21
unsigned EXTINT : 1; //20
unsigned EXT : 1; // External Insertion Status (1: External EXI device present) //19
unsigned ROMDIS : 1; // ROM Disable //18
unsigned :18;
};
UEXI_STATUS() {hex = 0;}
UEXI_STATUS(u32 _hex) {hex = _hex;}
};
// EXI Control Register
union UEXI_CONTROL
{
u32 hex;
struct
{
unsigned TSTART : 1;
unsigned DMA : 1;
unsigned RW : 2;
unsigned TLEN : 2;
unsigned :26;
};
};
UEXI_STATUS m_Status;
UEXI_CONTROL m_Control;
u32 m_DMAMemoryAddress;
u32 m_DMALength;
u32 m_ImmData;
// get device
IEXIDevice* GetDevice(u8 _CHIP_SELECT);
// Devices
enum
{
NUM_DEVICES = 3
};
IEXIDevice* m_pDevices[NUM_DEVICES];
public:
// channeId for debugging
u32 m_ChannelId;
// constructor
CEXIChannel();
// destructor
~CEXIChannel();
// Add a Device
void AddDevice(const TEXIDevices _device, const unsigned int _iSlot);
// Remove all devices
void RemoveDevices();
// update
void Update();
// Read32
void Read32(u32& _uReturnValue, const u32 _iRegister);
// isCausingInterrupt
bool isCausingInterrupt();
// Write32
void Write32(const u32 _iValue, const u32 _iRegister);
// update interrupts
void UpdateInterrupts();
};
#endif

View File

@ -0,0 +1,149 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Memmap.h"
#include "EXI_Device.h"
#include "EXI_DeviceIPL.h"
#include "EXI_DeviceMemoryCard.h"
#include "EXI_DeviceAD16.h"
#include "../Core.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////
// --- interface IEXIDevice ---
/////////////////////////////////////////////////////////////////////////////////////////////////////
void IEXIDevice::ImmWrite(u32 _uData, u32 _uSize)
{
while (_uSize--)
{
u8 uByte = _uData >> 24;
TransferByte(uByte);
_uData <<= 8;
}
}
u32 IEXIDevice::ImmRead(u32 _uSize)
{
u32 uResult = 0;
u32 uPosition = 0;
while (_uSize--)
{
u8 uByte = 0;
TransferByte(uByte);
uResult |= uByte << (24-(uPosition++ * 8));
}
return uResult;
}
void IEXIDevice::DMAWrite(u32 _uAddr, u32 _uSize)
{
// _dbg_assert_(EXPANSIONINTERFACE, 0);
while (_uSize--)
{
u8 uByte = Memory::Read_U8(_uAddr++);
TransferByte(uByte);
}
}
void IEXIDevice::DMARead(u32 _uAddr, u32 _uSize)
{
// _dbg_assert_(EXPANSIONINTERFACE, 0);
while (_uSize--)
{
u8 uByte = 0;
TransferByte(uByte);
Memory::Write_U8(uByte, _uAddr++);
}
};
bool IEXIDevice::IsPresent()
{
return false;
}
void IEXIDevice::Update()
{
}
bool IEXIDevice::IsInterruptSet()
{
return false;
}
void IEXIDevice::SetCS(int _iCS)
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// --- class CEXIDummy ---
/////////////////////////////////////////////////////////////////////////////////////////////////////
// just a dummy that logs reads and writes
// to be used for EXI devices we haven't emulated
class CEXIDummy : public IEXIDevice
{
std::string m_strName;
void TransferByte(u8& _byte) {}
public:
CEXIDummy(const std::string& _strName) :
m_strName(_strName)
{
}
virtual ~CEXIDummy(){}
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;}
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);}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////
// F A C T O R Y ////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
{
switch(_EXIDevice)
{
case EXIDEVICE_DUMMY:
return new CEXIDummy("Dummy");
break;
case EXIDEVICE_MEMORYCARD_A:
return new CEXIMemoryCard("MemoryCardA", Core::GetStartupParameter().m_strMemoryCardA);
break;
case EXIDEVICE_MEMORYCARD_B:
return new CEXIMemoryCard("MemoryCardB", Core::GetStartupParameter().m_strMemoryCardB);
break;
case EXIDEVICE_IPL:
return new CEXIIPL();
break;
case EXIDEVICE_AD16:
return new CEXIAD16();
break;
}
return NULL;
}

View File

@ -0,0 +1,62 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EXIDEVICE_H
#define _EXIDEVICE_H
#include "Common.h"
class IEXIDevice
{
private:
// transfer function for this function
virtual void TransferByte(u8& _byte) {};
public:
// immdeiate copy functions
virtual void ImmWrite(u32 _uData, u32 _uSize);
virtual u32 ImmRead(u32 _uSize);
// dma copy functions
virtual void DMAWrite(u32 _uAddr, u32 _uSize);
virtual void DMARead (u32 _uAddr, u32 _uSize);
// is the Device insert ??
virtual bool IsPresent();
virtual void SetCS(int _iCS);
// update
virtual void Update();
// is generating interrupt ?
virtual bool IsInterruptSet();
virtual ~IEXIDevice() {};
};
enum TEXIDevices
{
EXIDEVICE_DUMMY,
EXIDEVICE_MEMORYCARD_A,
EXIDEVICE_MEMORYCARD_B,
EXIDEVICE_IPL,
EXIDEVICE_AD16,
};
extern IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice);
#endif

View File

@ -0,0 +1,92 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../Core.h"
#include "EXI_Device.h"
#include "EXI_DeviceAD16.h"
CEXIAD16::CEXIAD16() :
m_uPosition(0),
m_uCommand(0)
{
m_uAD16Register.U32 = 0x00;
}
void CEXIAD16::SetCS(int cs)
{
if (cs)
m_uPosition = 0;
}
bool CEXIAD16::IsPresent()
{
return true;
}
void CEXIAD16::TransferByte(u8& _byte)
{
if (m_uPosition == 0)
{
m_uCommand = _byte;
}
else
{
switch(m_uCommand)
{
case init:
{
m_uAD16Register.U32 = 0x04120000;
switch(m_uPosition)
{
case 1: _dbg_assert_(EXPANSIONINTERFACE, (_byte == 0x00)); break; // just skip
case 2: _byte = m_uAD16Register.U8[0]; break;
case 3: _byte = m_uAD16Register.U8[1]; break;
case 4: _byte = m_uAD16Register.U8[2]; break;
case 5: _byte = m_uAD16Register.U8[3]; break;
}
}
break;
case write:
{
switch(m_uPosition)
{
case 1: m_uAD16Register.U8[0] = _byte; break;
case 2: m_uAD16Register.U8[1] = _byte; break;
case 3: m_uAD16Register.U8[2] = _byte; break;
case 4: m_uAD16Register.U8[3] = _byte; break;
}
}
break;
case read:
{
switch(m_uPosition)
{
case 1: _byte = m_uAD16Register.U8[0]; break;
case 2: _byte = m_uAD16Register.U8[1]; break;
case 3: _byte = m_uAD16Register.U8[2]; break;
case 4: _byte = m_uAD16Register.U8[3]; break;
}
}
break;
}
}
m_uPosition++;
}

View File

@ -0,0 +1,52 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EXIDEVICE_AD16_H
#define _EXIDEVICE_AD16_H
class CEXIAD16 : public IEXIDevice
{
public:
CEXIAD16();
//! SetCS
virtual void SetCS(int _iCS);
//! Is device present?
virtual bool IsPresent();
private:
enum
{
init = 0x00,
write = 0xa0,
read = 0xa2
};
union UAD16Reg
{
u32 U32;
u32 U8[4];
};
u32 m_uPosition;
u32 m_uCommand;
UAD16Reg m_uAD16Register;
virtual void TransferByte(u8& _uByte);
};
#endif

View File

@ -0,0 +1,276 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Timer.H"
#include "EXI_DeviceIPL.h"
#include "../Core.h"
#include "MemoryUtil.h"
// english
const unsigned char sram_dump[64] = {
0x04, 0x6B, 0xFB, 0x91, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x40,
0x05, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xD2, 0x2B, 0x29, 0xD5, 0xC7, 0xAA, 0x12, 0xCB,
0x21, 0x27, 0xD1, 0x53, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x86, 0x00, 0xFF, 0x4A, 0x00, 0x00, 0x00, 0x00
};
// german
const unsigned char sram_dump_german[64] ={
0x1F, 0x66, 0xE0, 0x96, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0xEA, 0x19, 0x40,
0x00, 0x00, 0x01, 0x3C, 0x12, 0xD5, 0xEA, 0xD3,
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, 0x84, 0xFF, 0x00, 0x00, 0x00, 0x00
};
static const char iplver[0x100] = "(C) 1999-2001 Nintendo. All rights reserved."
"(C) 1999 ArtX Inc. All rights reserved."
"PAL Revision 1.0 ";
CEXIIPL::CEXIIPL() :
m_uPosition(0),
m_uAddress(0),
m_uRWOffset(0),
m_count(0)
{
// load the IPL
m_pIPL = (u8*)AllocateMemoryPages(ROM_SIZE);
FILE* pStream = NULL;
pStream = fopen("./Data/font_ansi.bin", "rb");
if (pStream != NULL)
{
fseek(pStream, 0, SEEK_END);
size_t filesize = ftell(pStream);
rewind(pStream);
fread(m_pIPL + 0x001fcf00, 1, filesize, pStream);
fclose(pStream);
}
else
{
PanicAlert("Error: failed to load font_ansi.bin. Fonts may bug");
}
pStream = fopen("./Data/font_sjis.bin", "rb");
if (pStream != NULL)
{
fseek(pStream, 0, SEEK_END);
size_t filesize = ftell(pStream);
rewind(pStream);
fread(m_pIPL + 0x001aff00, 1, filesize, pStream);
fclose(pStream);
}
else
{
PanicAlert("Error: failed to load font_sjis.bin. Fonts may bug");
}
memcpy(m_pIPL, iplver, sizeof(iplver));
// clear RTC
memset(m_RTC, 0, sizeof(m_RTC));
// SRam
pStream = fopen(Core::GetStartupParameter().m_strSRAM.c_str(), "rb");
if (pStream != NULL)
{
fread(m_SRAM, 1, 64, pStream);
fclose(pStream);
}
else
{
memcpy(m_SRAM, sram_dump, sizeof(m_SRAM));
}
WriteProtectMemory(m_pIPL, ROM_SIZE);
m_uAddress = 0;
}
CEXIIPL::~CEXIIPL()
{
if (m_count > 0)
{
m_szBuffer[m_count] = 0x00;
//MessageBox(NULL, m_szBuffer, "last message", MB_OK);
}
if (m_pIPL != NULL)
{
FreeMemoryPages(m_pIPL, ROM_SIZE);
m_pIPL = NULL;
}
// SRam
FILE* pStream = NULL;
pStream = fopen(Core::GetStartupParameter().m_strSRAM.c_str(), "wb");
if (pStream != NULL)
{
fwrite(m_SRAM, 1, 64, pStream);
fclose(pStream);
}
}
void CEXIIPL::SetCS(int _iCS)
{
if (_iCS)
{ // cs transition to high
m_uPosition = 0;
}
}
bool CEXIIPL::IsPresent()
{
return true;
}
void CEXIIPL::TransferByte(u8& _uByte)
{
// the first 4 bytes must be the address
// if we havnt read it, do it now
if (m_uPosition < 4)
{
m_uAddress <<= 8;
m_uAddress |= _uByte;
m_uRWOffset = 0;
_uByte = 0xFF;
// check if the command is complete
if (m_uPosition == 3)
{
// get the time ...
u32 GCTime = CEXIIPL::GetGCTime();
u8* pGCTime = (u8*)&GCTime;
for (int i=0; i<4; i++)
{
m_RTC[i] = pGCTime[i^3];
}
#ifdef LOGGING
if ((m_uAddress & 0xF0000000) == 0xb0000000)
{
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something");
}
else if ((m_uAddress & 0xF0000000) == 0x30000000)
{
// wii stuff perhaps wii SRAM?
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something (perhaps SRAM?)");
}
// debug only
else if ((m_uAddress & 0x60000000) == 0)
{
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: IPL access");
}
else if ((m_uAddress & 0x7FFFFF00) == 0x20000000)
{
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: RTC access");
}
else if ((m_uAddress & 0x7FFFFF00) == 0x20000100)
{
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: SRAM access");
}
else if ((m_uAddress & 0x7FFFFF00) == 0x20010000)
{
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: UART");
}
else
{
_dbg_assert_(EXPANSIONINTERFACE, 0);
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: illegal address %08x", m_uAddress);
}
#endif
}
}
else
{
//
// --- ROM ---
//
if ((m_uAddress & 0x60000000) == 0)
{
if ((m_uAddress & 0x80000000) == 0)
_uByte = m_pIPL[((m_uAddress >> 6) & ROM_MASK) + m_uRWOffset];
}
//
// --- Real Time Clock (RTC) ---
//
else if ((m_uAddress & 0x7FFFFF00) == 0x20000000)
{
if (m_uAddress & 0x80000000)
m_RTC[(m_uAddress & 0x03) + m_uRWOffset] = _uByte;
else
_uByte = m_RTC[(m_uAddress & 0x03) + m_uRWOffset];
}
//
// --- SRam ---
//
else if ((m_uAddress & 0x7FFFFF00) == 0x20000100)
{
if (m_uAddress & 0x80000000)
m_SRAM[(m_uAddress & 0x3F) + m_uRWOffset] = _uByte;
else
_uByte = m_SRAM[(m_uAddress & 0x3F) + m_uRWOffset];
}
//
// --- UART ---
//
else if ((m_uAddress & 0x7FFFFF00) == 0x20010000)
{
if (m_uAddress & 0x80000000)
{
m_szBuffer[m_count++] = _uByte;
if ((m_count >= 256) || (_uByte == 0xD))
{
m_szBuffer[m_count] = 0x00;
LOG(OSREPORT, "%s", m_szBuffer);
memset(m_szBuffer, 0, sizeof(m_szBuffer));
m_count = 0;
}
}
else
_uByte = 0x01; // dunno
}
m_uRWOffset++;
}
m_uPosition++;
}
u32 CEXIIPL::GetGCTime()
{
// get sram bias
u32 Bias;
for (int i=0; i<4; i++)
{
((u8*)&Bias)[i] = sram_dump[0xc + (i^3)];
}
// get the time ...
const u32 cJanuary2000 = 0x386d35a1; // seconds between 1.1.1970 and 1.1.2000
__int64 ltime = Common::Timer::GetTimeSinceJan1970();
return ((u32)ltime - cJanuary2000 - Bias);
}

View File

@ -0,0 +1,68 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EXIDEVICE_IPL_H
#define _EXIDEVICE_IPL_H
#include "EXI_Device.h"
class CEXIIPL : public IEXIDevice
{
public:
CEXIIPL();
virtual ~CEXIIPL();
//! SetCS
virtual void SetCS(int _iCS);
//! Is device present?
bool IsPresent();
//! Get the GC Time
static u32 GetGCTime();
private:
enum
{
ROM_SIZE = 1024*1024*2,
ROM_MASK = (ROM_SIZE - 1)
};
//! IPL
u8* m_pIPL;
//! RealTimeClock
u8 m_RTC[4];
//! SRam
u8 m_SRAM[64];
//! Helper
u32 m_uPosition;
u32 m_uAddress;
u32 m_uRWOffset;
char m_szBuffer[256];
int m_count;
virtual void TransferByte(u8& _uByte);
};
#endif

View File

@ -0,0 +1,317 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../Core.h"
#include "../CoreTiming.h"
#include "EXI_Device.h"
#include "EXI_DeviceMemoryCard.h"
#define MC_STATUS_BUSY 0x80
#define MC_STATUS_UNLOCKED 0x40
#define MC_STATUS_SLEEP 0x20
#define MC_STATUS_ERASEERROR 0x10
#define MC_STATUS_PROGRAMEERROR 0x08
#define MC_STATUS_READY 0x01
CEXIMemoryCard::CEXIMemoryCard(const std::string& _rName, const std::string& _rFilename) :
m_strFilename(_rFilename)
{
nintendo_card_id = 0x00000010; // 16MBit nintendo card
card_id = 0xc221;
/* nintendo_card_id = 0x00000510; // 16MBit "bigben" card
card_id = 0xc243; */
memory_card_size = 2 * 1024 * 1024;
memory_card_content = new u8[memory_card_size];
memset(memory_card_content, 0xFF, memory_card_size);
FILE* pFile = NULL;
pFile = fopen(m_strFilename.c_str(), "rb");
if (pFile)
{
LOG(EXPANSIONINTERFACE, "Reading memory card %s", m_strFilename.c_str());
fread(memory_card_content, 1, memory_card_size, pFile);
fclose(pFile);
}
else
{
LOG(EXPANSIONINTERFACE, "No memory card found. Will create new.");
//MessageBox(0, "Could not read memory card file - starting with corrupt", m_strFilename.c_str(),0);
}
formatDelay = 0;
interruptSwitch = 0;
m_bInterruptSet = 0;
status = MC_STATUS_BUSY | MC_STATUS_UNLOCKED | MC_STATUS_READY;
}
void CEXIMemoryCard::Flush()
{
FILE* pFile = NULL;
pFile = fopen(m_strFilename.c_str(), "wb");
if (pFile)
{
fwrite(memory_card_content, memory_card_size, 1, pFile);
fclose(pFile);
}
else
{
PanicAlert("ERROR - could not write memory card file %s", m_strFilename.c_str());
}
}
void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate)
{
CEXIMemoryCard *ptr = reinterpret_cast<CEXIMemoryCard*>(userdata);
ptr->Flush();
}
CEXIMemoryCard::~CEXIMemoryCard()
{
Flush();
delete [] memory_card_content;
}
bool CEXIMemoryCard::IsPresent()
{
//return false;
return true;
}
void CEXIMemoryCard::SetCS(int cs)
{
if (cs) // not-selected to selected
m_uPosition = 0;
else
{
switch (command)
{
case cmdSectorErase:
if (m_uPosition > 2)
{
memset(memory_card_content + (address & (memory_card_size-1)), 0xFF, 0x2000);
status |= MC_STATUS_BUSY;
status &= ~MC_STATUS_READY;
//???
status |= MC_STATUS_READY;
status &= ~MC_STATUS_BUSY;
m_bInterruptSet = 1;
}
break;
case cmdChipErase:
if (m_uPosition > 2)
{
memset(memory_card_content, 0xFF, memory_card_size);
status &= ~0x80;
}
break;
case cmdPageProgram:
if (m_uPosition >= 5)
{
int count = m_uPosition - 5;
int i=0;
status &= ~0x80;
while (count--)
{
memory_card_content[address] = programming_buffer[i++];
i &= 127;
address = (address & ~0x1FF) | ((address+1) & 0x1FF);
}
status |= MC_STATUS_READY;
status &= ~MC_STATUS_BUSY;
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)
// But first we unschedule already scheduled flushes - no point in flushing once per page for a large write.
CoreTiming::RemoveEvent(&CEXIMemoryCard::FlushCallback);
CoreTiming::ScheduleEvent(500000000, &CEXIMemoryCard::FlushCallback, "Memory Card Flush", reinterpret_cast<u64>(this));
break;
}
}
}
void CEXIMemoryCard::Update()
{
if (formatDelay)
{
formatDelay--;
if (!formatDelay)
{
status |= MC_STATUS_READY;
status &= ~MC_STATUS_BUSY;
m_bInterruptSet = 1;
}
}
}
bool CEXIMemoryCard::IsInterruptSet()
{
if (interruptSwitch)
return m_bInterruptSet;
return false;
}
void CEXIMemoryCard::TransferByte(u8 &byte)
{
LOG(EXPANSIONINTERFACE, "EXI MEMCARD: > %02x", byte);
if (m_uPosition == 0)
{
command = byte; // first byte is command
byte = 0xFF; // would be tristate, but we don't care.
LOG(EXPANSIONINTERFACE, "EXI MEMCARD: command %02x", byte)
if(command == cmdClearStatus)
{
status &= ~MC_STATUS_PROGRAMEERROR;
status &= ~MC_STATUS_ERASEERROR;
status |= MC_STATUS_READY;
m_bInterruptSet = 0;
byte = 0xFF;
m_uPosition = 0;
}
}
else
{
switch (command)
{
case cmdNintendoID:
//
// nintendo card:
// 00 | 80 00 00 00 10 00 00 00
// "bigben" card:
// 00 | ff 00 00 05 10 00 00 00 00 00 00 00 00 00 00
// we do it the nintendo way.
if (m_uPosition == 1)
byte = 0x80; // dummy cycle
else
byte = (u8)(nintendo_card_id >> (24-(((m_uPosition-2) & 3) * 8)));
break;
case cmdReadArray:
switch (m_uPosition)
{
case 1: // AD1
address = byte << 17;
byte = 0xFF;
break;
case 2: // AD2
address |= byte << 9;
break;
case 3: // AD3
address |= (byte & 3) << 7;
break;
case 4: // BA
address |= (byte & 0x7F);
break;
}
if (m_uPosition > 1) // not specified for 1..8, anyway
{
byte = memory_card_content[address & (memory_card_size-1)];
// after 9 bytes, we start incrementing the address,
// but only the sector offset - the pointer wraps around
if (m_uPosition >= 9)
address = (address & ~0x1FF) | ((address+1) & 0x1FF);
}
break;
case cmdReadStatus:
// (unspecified for byte 1)
byte = status;
break;
case cmdReadID:
if (m_uPosition == 1) // (unspecified)
byte = (u8)(card_id >> 8);
else
byte = (u8)((m_uPosition & 1) ? (card_id) : (card_id >> 8));
break;
case cmdSectorErase:
switch (m_uPosition)
{
case 1: // AD1
address = byte << 17;
break;
case 2: // AD2
address |= byte << 9;
break;
}
byte = 0xFF;
break;
case cmdSetInterrupt:
if (m_uPosition==1)
{
interruptSwitch = byte;
}
byte = 0xFF;
break;
case cmdChipErase:
byte = 0xFF;
break;
case cmdPageProgram:
switch (m_uPosition)
{
case 1: // AD1
address = byte << 17;
break;
case 2: // AD2
address |= byte << 9;
break;
case 3: // AD3
address |= (byte & 3) << 7;
break;
case 4: // BA
address |= (byte & 0x7F);
break;
}
if(m_uPosition >= 5)
programming_buffer[((m_uPosition - 5) & 0x7F)] = byte; // wrap around after 128 bytes
byte = 0xFF;
break;
default:
LOG(EXPANSIONINTERFACE, "EXI MEMCARD: unknown command byte %02x\n", byte);
byte = 0xFF;
}
}
m_uPosition++;
LOG(EXPANSIONINTERFACE, "EXI MEMCARD: < %02x", byte);
}

View File

@ -0,0 +1,88 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EXI_DEVICEMEMORYCARD_H
#define _EXI_DEVICEMEMORYCARD_H
class CEXIMemoryCard : public IEXIDevice
{
public:
CEXIMemoryCard(const std::string& _rName, const std::string& _rFilename);
virtual ~CEXIMemoryCard();
//! SetCS
void SetCS(int cs);
// update
void Update();
// is generating interrupt ?
bool IsInterruptSet();
//! Is device present?
bool IsPresent();
private:
// This is scheduled whenever a page write is issued. The this pointer is passed
// through the userdata parameter, so that it can then call Flush on the right card.
static void FlushCallback(u64 userdata, int cyclesLate);
// Flushes the memory card contents to disk.
void Flush();
enum
{
cmdNintendoID = 0x00,
cmdReadArray = 0x52,
cmdArrayToBuffer = 0x53,
cmdSetInterrupt = 0x81,
cmdWriteBuffer = 0x82,
cmdReadStatus = 0x83,
cmdReadID = 0x85,
cmdReadErrorBuffer = 0x86,
cmdWakeUp = 0x87,
cmdSleep = 0x88,
cmdClearStatus = 0x89,
cmdSectorErase = 0xF1,
cmdPageProgram = 0xF2,
cmdExtraByteProgram = 0xF3,
cmdChipErase = 0xF4,
};
std::string m_strFilename;
//! memory card state
int interruptSwitch;
bool m_bInterruptSet;
int command;
int status;
u32 m_uPosition;
u8 programming_buffer[128];
u32 formatDelay;
//! memory card parameters
unsigned int nintendo_card_id, card_id;
unsigned int address;
int memory_card_size; //! in bytes, must be power of 2.
u8 *memory_card_content;
protected:
virtual void TransferByte(u8 &byte);
};
#endif

View File

@ -0,0 +1,135 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "GPFifo.h"
#include "PeripheralInterface.h"
#include "CommandProcessor.h"
#include "Memmap.h"
#include "../PowerPC/PowerPC.h"
namespace GPFifo
{
// 32 Byte gather pipe with extra space
// Overfilling is no problem (up to the real limit), CheckGatherPipe will blast the
// contents in nicely sized chunks
// 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 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,
// the same function could use both methods. Compile 2 different versions of each such block?
u8 m_gatherPipe[GATHER_PIPE_SIZE*16]; //more room, for the fastmodes
// pipe counter
u32 m_gatherPipeCount = 0;
void Init()
{
ResetGatherPipe();
}
void ResetGatherPipe()
{
m_gatherPipeCount = 0;
}
void CheckGatherPipe()
{
while (m_gatherPipeCount >= GATHER_PIPE_SIZE)
{
// copy the GatherPipe
memcpy(Memory::GetPointer(CPeripheralInterface::Fifo_CPUWritePointer), m_gatherPipe, GATHER_PIPE_SIZE);
// [F|RES]: i thought GP is forced to mem1 ... strange
// memcpy(&Memory::GetMainRAMPtr()[CPeripheralInterface::Fifo_CPUWritePointer], m_gatherPipe, GATHER_PIPE_SIZE);
// move back the spill bytes
m_gatherPipeCount -= GATHER_PIPE_SIZE;
// This could be dangerous, memmove or ?
// 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,
// the above memcpy could take care of that easily. TODO
memmove(m_gatherPipe, m_gatherPipe + GATHER_PIPE_SIZE, m_gatherPipeCount);
// increase the CPUWritePointer
CPeripheralInterface::Fifo_CPUWritePointer += GATHER_PIPE_SIZE;
if (CPeripheralInterface::Fifo_CPUWritePointer > CPeripheralInterface::Fifo_CPUEnd)
_assert_msg_(DYNA_REC,0,"ARGH");
if (CPeripheralInterface::Fifo_CPUWritePointer >= CPeripheralInterface::Fifo_CPUEnd)
CPeripheralInterface::Fifo_CPUWritePointer = CPeripheralInterface::Fifo_CPUBase;
CommandProcessor::GatherPipeBursted();
}
}
void Write8(const u8 _iValue, const u32 _iAddress)
{
// LOG(GPFIFO, "GPFIFO #%x: 0x%02x",CPeripheralInterface::Fifo_CPUWritePointer+m_gatherPipeCount, _iValue);
m_gatherPipe[m_gatherPipeCount] = _iValue;
m_gatherPipeCount++;
CheckGatherPipe();
}
void Write16(const u16 _iValue, const u32 _iAddress)
{
// LOG(GPFIFO, "GPFIFO #%x: 0x%04x",CPeripheralInterface::Fifo_CPUWritePointer+m_gatherPipeCount, _iValue);
*(u16*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap16(_iValue);
m_gatherPipeCount+=2;
CheckGatherPipe();
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
#ifdef _DEBUG
float floatvalue = *(float*)&_iValue;
// LOG(GPFIFO, "GPFIFO #%x: 0x%08x / %f",CPeripheralInterface::Fifo_CPUWritePointer+m_gatherPipeCount, _iValue, floatvalue);
#endif
*(u32*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap32(_iValue);
m_gatherPipeCount+=4;
CheckGatherPipe();
}
void FastWrite8(const u8 _iValue)
{
m_gatherPipe[m_gatherPipeCount] = _iValue;
m_gatherPipeCount++;
}
void FastWrite16(const u16 _iValue)
{
*(u16*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap16(_iValue);
m_gatherPipeCount += 2;
}
void FastWrite32(const u32 _iValue)
{
*(u32*)(&m_gatherPipe[m_gatherPipeCount]) = Common::swap32(_iValue);
m_gatherPipeCount += 4;
}
void FastWriteEnd()
{
CheckGatherPipe();
}
} // end of namespace GPFifo

View File

@ -0,0 +1,52 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _GPFIFO_H
#define _GPFIFO_H
#include "Common.h"
namespace GPFifo
{
enum
{
GATHER_PIPE_SIZE = 32
};
// Init
void Init();
// ResetGatherPipe
void ResetGatherPipe();
void CheckGatherPipe();
// Write
void HWCALL Write8(const u8 _iValue, const u32 _iAddress);
void HWCALL Write16(const u16 _iValue, const u32 _iAddress);
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
// These expect pre-byteswapped values
// Also there's an upper limit of about 512 per batch
// Most likely these should be inlined into JIT instead
void HWCALL FastWrite8(const u8 _iValue);
void HWCALL FastWrite16(const u16 _iValue);
void HWCALL FastWrite32(const u32 _iValue);
};
#endif

View File

@ -0,0 +1,76 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "../Core.h"
#include "HW.h"
#include "../PowerPC/PowerPC.h"
#include "CPU.h"
#include "CommandProcessor.h"
#include "DSP.h"
#include "DVDInterface.h"
#include "EXI.h"
#include "GPFifo.h"
#include "Memmap.h"
#include "PeripheralInterface.h"
#include "PixelEngine.h"
#include "SerialInterface.h"
#include "AudioInterface.h"
#include "VideoInterface.h"
#include "WII_IPC.h"
#include "../Plugins/Plugin_Video.h"
#include "SystemTimers.h"
#include "../IPC_HLE/WII_IPC_HLE.h"
#define CURVERSION 0x0001
namespace HW
{
void Init()
{
// Init the whole Hardware
PixelEngine::Init();
CommandProcessor::Init();
VideoInterface::Init();
SerialInterface::Init();
CPeripheralInterface::Init();
Memory::Init();
DSP::Init();
DVDInterface::Init();
GPFifo::Init();
ExpansionInterface::Init();
CCPU::Init();
SystemTimers::Init();
WII_IPC_HLE_Interface::Init();
WII_IPCInterface::Init();
}
void Shutdown()
{
SystemTimers::Shutdown();
CCPU::Shutdown();
ExpansionInterface::Shutdown();
DVDInterface::Shutdown();
DSP::Shutdown();
Memory::Shutdown();
SerialInterface::Shutdown();
WII_IPC_HLE_Interface::Shutdown();
WII_IPCInterface::Shutdown();
}
}

View File

@ -0,0 +1,33 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _HW_H
#define _HW_H
#include "Common.h"
namespace HW
{
void Init();
void Shutdown();
/*
void LoadState(const char* _szFilename);
void SaveState(const char* _szFilename);
*/
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,129 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _MEMMAP_H
#define _MEMMAP_H
#include <string>
#include "Common.h"
typedef void (HWCALL *writeFn8 )(const u8, const u32);
typedef void (HWCALL *writeFn16)(const u16,const u32);
typedef void (HWCALL *writeFn32)(const u32,const u32);
typedef void (HWCALL *writeFn64)(const u64,const u32);
typedef void (HWCALL *readFn8 )(u8&, const u32);
typedef void (HWCALL *readFn16)(u16&, const u32);
typedef void (HWCALL *readFn32)(u32&, const u32);
typedef void (HWCALL *readFn64)(u64&, const u32);
namespace Memory
{
// base is a pointer to the base of the memory map. Yes, some MMU tricks are used to set up
// a full GC or Wii memory map in process memory.
// on 32-bit, you have to mask your offsets with 0x3FFFFFFF. This means that some things are mirrored,
// but eh... it works.
extern u8 *base;
extern u8* m_pRAM;
extern u8* m_pL1Cache;
// the size should be 24mb only, but the RAM_MASK wouldn't work anymore
enum
{
RAM_SIZE = 0x2000000,
RAM_MASK = 0x1FFFFFF,
FAKEVMEM_SIZE = 0x2000000,
FAKEVMEM_MASK = 0x1FFFFFF,
REALRAM_SIZE = 0x1800000,
L1_CACHE_SIZE = 0x40000,
L1_CACHE_MASK = 0x3FFFF,
EFB_SIZE = 0x200000,
EFB_MASK = 0x1FFFFF,
IO_SIZE = 0x10000,
EXRAM_SIZE = 0x4000000,
EXRAM_MASK = 0x3FFFFFF,
#ifdef _M_IX86
MEMVIEW32_MASK = 0x3FFFFFFF,
#endif
};
bool Init();
bool Shutdown();
void Clear();
bool AreMemoryBreakpointsActivated();
//ONLY for use by GUI
u8 ReadUnchecked_U8(const u32 _Address);
u32 ReadUnchecked_U32(const u32 _Address);
void WriteUnchecked_U8(const u8 _Data, const u32 _Address);
void WriteUnchecked_U32(const u32 _Data, const u32 _Address);
void InitHWMemFuncs();
void InitHWMemFuncsWii();
u32 Read_Instruction(const u32 _Address);
bool IsRAMAddress(const u32 addr);
writeFn32 GetHWWriteFun32(const u32 _Address);
inline u8* GetCachePtr() {return m_pL1Cache;}
inline u8* GetMainRAMPtr() {return m_pRAM;}
inline u32 ReadFast32(const u32 _Address)
{
#ifdef _M_IX86
return ReadUnchecked_U32(_Address);
#elif defined(_M_X64)
return Common::swap32(*(u32 *)(base + _Address));
#endif
}
//For use by emulator
u8 Read_U8(const u32 _Address);
u16 Read_U16(const u32 _Address);
u32 Read_U32(const u32 _Address);
u64 Read_U64(const u32 _Address);
void Write_U8(const u8 _Data, const u32 _Address);
void Write_U16(const u16 _Data, const u32 _Address);
void Write_U32(const u32 _Data, const u32 _Address);
void Write_U64(const u64 _Data, const u32 _Address);
void WriteHW_U32(const u32 _Data, const u32 _Address);
void GetString(std::string& _string, const u32 _Address);
void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 size);
void ReadBigEData(u8 *_pDest, const u32 _Address, const u32 size);
u8* GetPointer(const u32 _Address);
void DMA_LCToMemory(const u32 _iMemAddr, const u32 _iCacheAddr, const u32 _iNumBlocks);
void DMA_MemoryToLC(const u32 _iCacheAddr, const u32 _iMemAddr, const u32 _iNumBlocks);
void Memset(const u32 _Address, const u8 _Data, const u32 _iLength);
void SDRUpdated();
enum XCheckTLBFlag
{
FLAG_NO_EXCEPTION,
FLAG_READ,
FLAG_WRITE,
FLAG_OPCODE,
};
u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag);
extern u32 pagetable_base;
extern u32 pagetable_hashmask;
};
#endif

View File

@ -0,0 +1,86 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../PowerPC/PowerPC.h"
#include "MemoryInterface.h"
namespace MemoryInterface
{
// internal hardware addresses
enum
{
MEM_CHANNEL0_HI = 0x000,
MEM_CHANNEL0_LO = 0x002,
MEM_CHANNEL1_HI = 0x004,
MEM_CHANNEL1_LO = 0x006,
MEM_CHANNEL2_HI = 0x008,
MEM_CHANNEL2_LO = 0x00A,
MEM_CHANNEL3_HI = 0x00C,
MEM_CHANNEL3_LO = 0x00E,
MEM_CHANNEL_CTRL = 0x010
};
struct MIMemStruct
{
u32 Channel0_Addr;
u32 Channel1_Addr;
u32 Channel2_Addr;
u32 Channel3_Addr;
u32 Channel_Ctrl;
};
MIMemStruct miMem;
void Read16(u16& _uReturnValue, const u32 _iAddress)
{
//0x30 -> 0x5a : gp memory metrics
LOG(MEMMAP, "(r16) 0x%04x @ 0x%08x", 0, _iAddress);
_uReturnValue = 0;
}
void Read32(u32& _uReturnValue, const u32 _iAddress)
{
LOG(MEMMAP, "(r32) 0x%08x @ 0x%08x", 0, _iAddress);
_uReturnValue = 0;
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
LOG(MEMMAP, "(w32) 0x%08x @ 0x%08x", _iValue, _iAddress);
}
//TODO : check
void Write16(const u16 _iValue, const u32 _iAddress)
{
LOG(MEMMAP, "(w16) 0x%04x @ 0x%08x", _iValue, _iAddress);
switch(_iAddress & 0xFFF)
{
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_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_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_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_CHANNEL_CTRL: miMem.Channel_Ctrl = _iValue; return;
}
}
} // end of namespace MemoryInterface

View File

@ -0,0 +1,29 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _MEMORYINTERFACE_H
#define _MEMORYINTERFACE_H
namespace MemoryInterface
{
void HWCALL Read16(u16& _uReturnValue, const u32 _iAddress);
void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
void HWCALL Write16(const u16 _iValue, const u32 _iAddress);
} // end of namespace MemoryInterface
#endif

View File

@ -0,0 +1,211 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <stdio.h>
#include "../PowerPC/PowerPC.h"
#include "../HW/CPU.h"
#include "PeripheralInterface.h"
#include "GPFifo.h"
u32 volatile CPeripheralInterface::m_InterruptMask;
u32 volatile CPeripheralInterface::m_InterruptCause;
// addresses for CPU fifo accesses
u32 CPeripheralInterface::Fifo_CPUBase;
u32 CPeripheralInterface::Fifo_CPUEnd;
u32 CPeripheralInterface::Fifo_CPUWritePointer;
void CPeripheralInterface::Init()
{
m_InterruptMask = 0;
m_InterruptCause = 0;
Fifo_CPUBase = 0;
Fifo_CPUEnd = 0;
Fifo_CPUWritePointer = 0;
m_InterruptCause |= INT_CAUSE_RST_BUTTON; // Reset button state
}
void CPeripheralInterface::Read32(u32& _uReturnValue, const u32 _iAddress)
{
//LOG(PERIPHERALINTERFACE, "(r32) 0x%08x", _iAddress);
switch(_iAddress & 0xFFF)
{
case PI_INTERRUPT_CAUSE:
_uReturnValue = m_InterruptCause;
return;
case PI_INTERRUPT_MASK:
_uReturnValue = m_InterruptMask;
return;
case PI_FIFO_BASE:
LOG(PERIPHERALINTERFACE,"read cpu fifo base, value = %08x",Fifo_CPUBase);
_uReturnValue = Fifo_CPUBase;
return;
case PI_FIFO_END:
LOG(PERIPHERALINTERFACE,"read cpu fifo end, value = %08x",Fifo_CPUEnd);
_uReturnValue = Fifo_CPUEnd;
return;
case PI_FIFO_WPTR:
LOG(PERIPHERALINTERFACE,"read writepointer, value = %08x",Fifo_CPUWritePointer);
_uReturnValue = Fifo_CPUWritePointer; //really writes in 32-byte chunks
// Monk's gcube does some crazy align trickery here.
return;
case PI_RESET_CODE:
_uReturnValue = 0x80000000;
return;
case PI_MB_REV:
_uReturnValue = 0x20000000; // HW2 production board
return;
default:
LOG(PERIPHERALINTERFACE,"!!!!Unknown write!!!! 0x%08x", _iAddress);
break;
}
_uReturnValue = 0xAFFE0000;
}
void CPeripheralInterface::Write32(const u32 _uValue, const u32 _iAddress)
{
LOG(PERIPHERALINTERFACE, "(w32) 0x%08x @ 0x%08x", _uValue, _iAddress);
switch(_iAddress & 0xFFF)
{
case PI_INTERRUPT_CAUSE:
m_InterruptCause &= ~_uValue; //writes turns them off
UpdateException();
return;
case PI_INTERRUPT_MASK:
m_InterruptMask = _uValue;
LOG(PERIPHERALINTERFACE,"New Interrupt mask: %08x",m_InterruptMask);
UpdateException();
return;
case PI_FIFO_BASE:
Fifo_CPUBase = _uValue & 0xFFFFFFE0;
LOG(PERIPHERALINTERFACE,"Fifo base = %08x", _uValue);
break;
case PI_FIFO_END:
Fifo_CPUEnd = _uValue & 0xFFFFFFE0;
LOG(PERIPHERALINTERFACE,"Fifo end = %08x", _uValue);
break;
case PI_FIFO_WPTR:
Fifo_CPUWritePointer = _uValue & 0xFFFFFFE0;
LOG(PERIPHERALINTERFACE,"Fifo writeptr = %08x", _uValue);
break;
case PI_FIFO_RESET:
// Fifo_CPUWritePointer = Fifo_CPUBase; ??
// PanicAlert("Unknown write to PI_FIFO_RESET (%08x)", _uValue);
break;
case PI_RESET_CODE:
{
LOG(PERIPHERALINTERFACE,"PI Reset = %08x ???", _uValue);
if ((_uValue != 0x80000001) && (_uValue != 0x80000005)) // DVDLowReset
{
TCHAR szTemp[256];
sprintf(szTemp, "Unknown write to PI_RESET_CODE (%08x)", _uValue);
PanicAlert(szTemp);
}
}
break;
default:
LOG(PERIPHERALINTERFACE,"!!!!Unknown write!!!! 0x%08x", _iAddress);
PanicAlert("Unknown write to PI");
break;
}
}
void CPeripheralInterface::UpdateException()
{
if ((m_InterruptCause & m_InterruptMask) != 0)
PowerPC::ppcState.Exceptions |= EXCEPTION_EXTERNAL_INT;
else
PowerPC::ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
}
const char *CPeripheralInterface::Debug_GetInterruptName(InterruptCause _causemask)
{
switch (_causemask)
{
case INT_CAUSE_ERROR: return "INT_CAUSE_ERROR";
case INT_CAUSE_DI: return "INT_CAUSE_DI";
case INT_CAUSE_RSW: return "INT_CAUSE_RSW";
case INT_CAUSE_SI: return "INT_CAUSE_SI";
case INT_CAUSE_EXI: return "INT_CAUSE_EXI";
case INT_CAUSE_AUDIO: return "INT_CAUSE_AUDIO";
case INT_CAUSE_DSP: return "INT_CAUSE_DSP";
case INT_CAUSE_MEMORY: return "INT_CAUSE_MEMORY";
case INT_CAUSE_VI: return "INT_CAUSE_VI";
case INT_CAUSE_PE_TOKEN: return "INT_CAUSE_PE_TOKEN";
case INT_CAUSE_PE_FINISH: return "INT_CAUSE_PE_FINISH";
case INT_CAUSE_CP: return "INT_CAUSE_CP";
case INT_CAUSE_DEBUG: return "INT_CAUSE_DEBUG";
case INT_CAUSE_WII_IPC: return "INT_CAUSE_WII_IPC";
case INT_CAUSE_HSP: return "INT_CAUSE_HSP";
case INT_CAUSE_RST_BUTTON: return "INT_CAUSE_RST_BUTTON";
}
return "!!! ERROR-unknown Interrupt !!!";
}
void CPeripheralInterface::SetInterrupt(InterruptCause _causemask, bool _bSet)
{
//TODO(ector): add sanity check that current thread id is cpu thread
if (_bSet && !(m_InterruptCause & (u32)_causemask))
{
LOG(PERIPHERALINTERFACE,"Setting Interrupt %s (%s)",Debug_GetInterruptName(_causemask), "set");
}
if (!_bSet && (m_InterruptCause & (u32)_causemask))
{
LOG(PERIPHERALINTERFACE,"Setting Interrupt %s (%s)",Debug_GetInterruptName(_causemask), "clear");
}
if (_bSet)
m_InterruptCause |= (u32)_causemask;
else
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
// if the interrupt cause is eliminated. that isnt done by software (afaik)
UpdateException();
}
void CPeripheralInterface::SetResetButton(bool _bSet)
{
if (_bSet)
m_InterruptCause &= ~INT_CAUSE_RST_BUTTON;
else
m_InterruptCause |= INT_CAUSE_RST_BUTTON;
}

View File

@ -0,0 +1,113 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _PERIPHERALINTERFACE_H
#define _PERIPHERALINTERFACE_H
#include "Common.h"
//
// PERIPHERALINTERFACE
// Handles communication with cpu services like the write gatherer used for fifos, and interrupts
//
class CPeripheralInterface
{
friend class CRegisters;
public:
enum InterruptCause
{
INT_CAUSE_ERROR = 0x1, // ?
INT_CAUSE_RSW = 0x2, // Reset Switch
INT_CAUSE_DI = 0x4, // DVD interrupt
INT_CAUSE_SI = 0x8, // Serial interface
INT_CAUSE_EXI = 0x10, // Expansion interface
INT_CAUSE_AUDIO = 0x20, // Audio Interface Streaming
INT_CAUSE_DSP = 0x40, // DSP interface
INT_CAUSE_MEMORY = 0x80, // Memory interface
INT_CAUSE_VI = 0x100, // Video interface
INT_CAUSE_PE_TOKEN = 0x200, // GP Token
INT_CAUSE_PE_FINISH = 0x400, // GP Finished
INT_CAUSE_CP = 0x800, // Command Fifo
INT_CAUSE_DEBUG = 0x1000, // ?
INT_CAUSE_HSP = 0x2000, // High Speed Port
INT_CAUSE_WII_IPC = 0x4000, // Wii IPC
INT_CAUSE_RST_BUTTON = 0x10000 // ResetButtonState (1 = unpressed, 0 = pressed)
};
private:
// internal hardware addresses
enum
{
PI_INTERRUPT_CAUSE = 0x000,
PI_INTERRUPT_MASK = 0x004,
PI_FIFO_BASE = 0x00C,
PI_FIFO_END = 0x010,
PI_FIFO_WPTR = 0x014,
PI_FIFO_RESET = 0x018, // ??? - GXAbortFrameWrites to it
PI_RESET_CODE = 0x024,
PI_MB_REV = 0x02C,
};
//This must always be byteswapped :( (UNUSED ATM)
struct PIRegMem
{
u32 rInterruptCause; //00
u32 rInterruptMask; //04
u32 unused0; //08
u32 FifoBase; //0C
u32 FifoEnd; //10
u32 FifoWptr; //14
u32 FifoReset; //18
u32 unused1; //1C
u32 unused2; //20
u32 ResetCode; //24
u32 unused3; //28
u32 MBRev; //2C
};
static volatile u32 m_InterruptMask;
static volatile u32 m_InterruptCause;
static void UpdateException();
// Debug_GetInterruptName
static const char* Debug_GetInterruptName(InterruptCause _causemask);
public:
static u32 Fifo_CPUBase;
static u32 Fifo_CPUEnd;
static u32 Fifo_CPUWritePointer;
static void Init();
static void SetInterrupt(InterruptCause _causemask, bool _bSet=true);
// Read32
static void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
// Write32
static void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
// SetResetButton (you have to release the button again to make a reset)
static void SetResetButton(bool _bSet);
};
#endif

View File

@ -0,0 +1,178 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "PixelEngine.h"
#include "../CoreTiming.h"
#include "../PowerPC/PowerPC.h"
#include "PeripheralInterface.h"
#include "CommandProcessor.h"
#include "CPU.h"
#include "../Core.h"
namespace PixelEngine
{
// internal hardware addresses
enum
{
CTRL_REGISTER = 0x00a,
TOKEN_REG = 0x00e,
};
// fifo Control Register
union UPECtrlReg
{
struct
{
unsigned PETokenEnable : 1;
unsigned PEFinishEnable : 1;
unsigned PEToken : 1; // write only
unsigned PEFinish : 1; // write only
unsigned : 12;
};
u16 Hex;
UPECtrlReg() {Hex = 0; }
UPECtrlReg(u16 _hex) {Hex = _hex; }
};
UPECtrlReg g_ctrlReg;
u16 g_token = 0;
bool g_bSignalTokenInterrupt;
bool g_bSignalFinishInterrupt;
void UpdateInterrupts();
void Init()
{
g_token = 0;
g_ctrlReg.Hex = 0;
}
void Read16(u16& _uReturnValue, const u32 _iAddress)
{
LOG(PIXELENGINE, "(r16): 0x%08x", _iAddress);
switch (_iAddress & 0xFFF)
{
case CTRL_REGISTER:
_uReturnValue = g_ctrlReg.Hex;
return;
case TOKEN_REG:
_uReturnValue = g_token;
return;
default:
LOG(PIXELENGINE,"(unknown)");
break;
}
_uReturnValue = 0x001;
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
LOG(PIXELENGINE, "(w32): 0x%08x @ 0x%08x",_iValue,_iAddress);
}
void Write16(const u16 _iValue, const u32 _iAddress)
{
LOG(PIXELENGINE, "(w16): 0x%04x @ 0x%08x",_iValue,_iAddress);
switch(_iAddress & 0xFFF)
{
case CTRL_REGISTER:
{
UPECtrlReg tmpCtrl(_iValue);
if (tmpCtrl.PEToken) g_bSignalTokenInterrupt = false;
if (tmpCtrl.PEFinish) g_bSignalFinishInterrupt = false;
g_ctrlReg.PETokenEnable = tmpCtrl.PETokenEnable;
g_ctrlReg.PEFinishEnable = tmpCtrl.PEFinishEnable;
g_ctrlReg.PEToken = 0; // this flag is write only
g_ctrlReg.PEFinish = 0; // this flag is write only
UpdateInterrupts();
}
break;
case TOKEN_REG:
LOG(PIXELENGINE,"WEIRD: program wrote token: %i",_iValue);
//only the gx pipeline is supposed to be able to write here
g_token = _iValue;
break;
}
}
bool AllowIdleSkipping()
{
return !Core::g_CoreStartupParameter.bUseDualCore || (!g_ctrlReg.PETokenEnable && !g_ctrlReg.PEFinishEnable);
}
void UpdateInterrupts()
{
// check if there is a token-interrupt
if (g_bSignalTokenInterrupt & g_ctrlReg.PETokenEnable)
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_TOKEN, true);
else
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_TOKEN, false);
// check if there is a finish-interrupt
if (g_bSignalFinishInterrupt & g_ctrlReg.PEFinishEnable)
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_FINISH, true);
else
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_FINISH, false);
}
void SetToken_OnMainThread(u64 userdata, int cyclesLate)
{
// In the future: schedule callback that does the rest of this function
// This way we will be threadsafe
if (userdata >> 16)
g_bSignalTokenInterrupt = true;
g_token = (u16)(userdata & 0xFFFF);
LOG(PIXELENGINE, "VIDEO Plugin wrote token: %i", g_token);
UpdateInterrupts();
}
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
{
g_bSignalFinishInterrupt = 1;
UpdateInterrupts();
}
// SetToken
// THIS IS EXECUTED FROM VIDEO THREAD
void SetToken(const unsigned __int16 _token, const int _bSetTokenAcknowledge)
{
CoreTiming::ScheduleEvent_Threadsafe(
0, SetToken_OnMainThread, "SetToken", _token | (_bSetTokenAcknowledge << 16));
}
// SetFinish
// THIS IS EXECUTED FROM VIDEO THREAD
void SetFinish()
{
CoreTiming::ScheduleEvent_Threadsafe(
0, SetFinish_OnMainThread, "SetFinish");
LOG(PIXELENGINE, "VIDEO Set Finish");
}
} // end of namespace PixelEngine

View File

@ -0,0 +1,41 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _PIXELENGINE_H
#define _PIXELENGINE_H
#include "Common.h"
namespace PixelEngine
{
void Init();
// Read
void HWCALL Read16(u16& _uReturnValue, const u32 _iAddress);
// Write
void HWCALL Write16(const u16 _iValue, const u32 _iAddress);
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
// gfx plugin support
void SetToken(const unsigned __int16 _token, const int _bSetTokenAcknowledge);
void SetFinish(void);
bool AllowIdleSkipping();
} // end of namespace PixelEngine
#endif

View File

@ -0,0 +1,536 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <string.h>
#include "SerialInterface.h"
#include "SerialInterface_Devices.h"
#include "PeripheralInterface.h"
#include "CPU.h"
#include "../PowerPC/PowerPC.h"
namespace SerialInterface
{
// SI Interrupt Types
enum SIInterruptType
{
INT_RDSTINT = 0,
INT_TCINT = 1,
};
// SI number of channels
enum
{
NUMBER_OF_CHANNELS = 0x04
};
// SI Internal Hardware Addresses
enum
{
SI_CHANNEL_0_OUT = 0x00,
SI_CHANNEL_0_IN_HI = 0x04,
SI_CHANNEL_0_IN_LO = 0x08,
SI_CHANNEL_1_OUT = 0x0C,
SI_CHANNEL_1_IN_HI = 0x10,
SI_CHANNEL_1_IN_LO = 0x14,
SI_CHANNEL_2_OUT = 0x18,
SI_CHANNEL_2_IN_HI = 0x1C,
SI_CHANNEL_2_IN_LO = 0x20,
SI_CHANNEL_3_OUT = 0x24,
SI_CHANNEL_3_IN_HI = 0x28,
SI_CHANNEL_3_IN_LO = 0x2C,
SI_POLL = 0x30,
SI_COM_CSR = 0x34,
SI_STATUS_REG = 0x38,
SI_EXI_CLOCK_COUNT = 0x3C,
};
// SI Channel Output
union USIChannelOut
{
u32 Hex;
struct
{
unsigned OUTPUT1 : 8;
unsigned OUTPUT0 : 8;
unsigned CMD : 8;
unsigned : 8;
};
};
// SI Channel Input High u32
union USIChannelIn_Hi
{
u32 Hex;
struct
{
unsigned INPUT3 : 8;
unsigned INPUT2 : 8;
unsigned INPUT1 : 8;
unsigned INPUT0 : 6;
unsigned ERRLATCH : 1; // 0: no error 1: Error latched. Check SISR.
unsigned ERRSTAT : 1; // 0: no error 1: error on last transfer
};
};
// SI Channel Input Low u32
union USIChannelIn_Lo
{
u32 Hex;
struct
{
unsigned INPUT7 : 8;
unsigned INPUT6 : 8;
unsigned INPUT5 : 8;
unsigned INPUT4 : 8;
};
};
// SI Channel
struct SSIChannel
{
USIChannelOut m_Out;
USIChannelIn_Hi m_InHi;
USIChannelIn_Lo m_InLo;
ISIDevice* m_pDevice;
};
// SI Poll: Controls how often a device is polled
union USIPoll
{
u32 Hex;
struct
{
unsigned VBCPY3 : 1;
unsigned VBCPY2 : 1;
unsigned VBCPY1 : 1;
unsigned VBCPY0 : 1;
unsigned EN3 : 1;
unsigned EN2 : 1;
unsigned EN1 : 1;
unsigned EN0 : 1;
unsigned Y : 10;
unsigned X : 10;
unsigned : 6;
};
};
// SI Communication Control Status Register
union USIComCSR
{
u32 Hex;
struct
{
unsigned TSTART : 1;
unsigned CHANNEL : 2; // determines which SI channel will be used the communication interface.
unsigned : 5;
unsigned INLNGTH : 7;
unsigned : 1;
unsigned OUTLNGTH : 7; // Communication Channel Output Length in bytes
unsigned : 4;
unsigned RDSTINTMSK : 1; // Read Status Interrupt Status Mask
unsigned RDSTINT : 1; // Read Status Interrupt Status
unsigned COMERR : 1; // Communication Error (set 0)
unsigned TCINTMSK : 1; // Transfer Complete Interrupt Mask
unsigned TCINT : 1; // Transfer Complete Interrupt
};
USIComCSR() {Hex = 0;}
USIComCSR(u32 _hex) {Hex = _hex;}
};
// SI Status Register
union USIStatusReg
{
u32 Hex;
struct
{
unsigned UNRUN3 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error
unsigned OVRUN3 : 1; // (RWC) write 1: bit cleared read 1 overrun error
unsigned COLL3 : 1; // (RWC) write 1: bit cleared read 1 collision error
unsigned NOREP3 : 1; // (RWC) write 1: bit cleared read 1 response error
unsigned WRST3 : 1; // (R) 1: buffer channel0 not copied
unsigned RDST3 : 1; // (R) 1: new Data available
unsigned : 2; // 7:6
unsigned UNRUN2 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error
unsigned OVRUN2 : 1; // (RWC) write 1: bit cleared read 1 overrun error
unsigned COLL2 : 1; // (RWC) write 1: bit cleared read 1 collision error
unsigned NOREP2 : 1; // (RWC) write 1: bit cleared read 1 response error
unsigned WRST2 : 1; // (R) 1: buffer channel0 not copied
unsigned RDST2 : 1; // (R) 1: new Data available
unsigned : 2; // 15:14
unsigned UNRUN1 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error
unsigned OVRUN1 : 1; // (RWC) write 1: bit cleared read 1 overrun error
unsigned COLL1 : 1; // (RWC) write 1: bit cleared read 1 collision error
unsigned NOREP1 : 1; // (RWC) write 1: bit cleared read 1 response error
unsigned WRST1 : 1; // (R) 1: buffer channel0 not copied
unsigned RDST1 : 1; // (R) 1: new Data available
unsigned : 2; // 23:22
unsigned UNRUN0 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error
unsigned OVRUN0 : 1; // (RWC) write 1: bit cleared read 1 overrun error
unsigned COLL0 : 1; // (RWC) write 1: bit cleared read 1 collision error
unsigned NOREP0 : 1; // (RWC) write 1: bit cleared read 1 response error
unsigned WRST0 : 1; // (R) 1: buffer channel0 not copied
unsigned RDST0 : 1; // (R) 1: new Data available
unsigned : 1;
unsigned WR : 1; // (RW) write 1 start copy, read 0 copy done
};
USIStatusReg() {Hex = 0;}
USIStatusReg(u32 _hex) {Hex = _hex;}
};
// SI EXI Clock Count
union USIEXIClockCount
{
u32 Hex;
struct
{
unsigned LOCK : 1;
unsigned : 30;
};
};
SSIChannel g_Channel[NUMBER_OF_CHANNELS];
USIPoll g_Poll;
USIComCSR g_ComCSR;
USIStatusReg g_StatusReg;
USIEXIClockCount g_EXIClockCount;
u8 g_SIBuffer[128];
static void GenerateSIInterrupt(SIInterruptType _SIInterrupt);
void RunSIBuffer();
void UpdateInterrupts();
void Init()
{
for (int i = 0; i < NUMBER_OF_CHANNELS; i++)
{
g_Channel[i].m_Out.Hex = 0;
g_Channel[i].m_InHi.Hex = 0;
g_Channel[i].m_InLo.Hex = 0;
}
g_Channel[0].m_pDevice = new CSIDevice_GCController(0);
g_Channel[1].m_pDevice = new CSIDevice_Dummy(1);//new CSIDevice_GCController(1);
g_Channel[2].m_pDevice = new CSIDevice_Dummy(2);//new CSIDevice_GCController(2);
g_Channel[3].m_pDevice = new CSIDevice_Dummy(3);//new CSIDevice_GCController(3);
g_Poll.Hex = 0;
g_ComCSR.Hex = 0;
g_StatusReg.Hex = 0;
g_EXIClockCount.Hex = 0;
memset(g_SIBuffer, 0xce, 128);
}
void Shutdown()
{
for (int i=0; i<NUMBER_OF_CHANNELS; i++)
{
delete g_Channel[i].m_pDevice;
g_Channel[i].m_pDevice = NULL;
}
}
void Read32(u32& _uReturnValue, const u32 _iAddress)
{
LOG(SERIALINTERFACE, "(r32): 0x%08x", _iAddress);
// SIBuffer
if ((_iAddress >= 0xCC006480 && _iAddress < 0xCC006500) ||
(_iAddress >= 0xCD006480 && _iAddress < 0xCD006500))
{
_uReturnValue = *(u32*)&g_SIBuffer[_iAddress & 0x7F];
return;
}
// registers
switch (_iAddress & 0x3FF)
{
//===================================================================================================
// Channel 0
//===================================================================================================
case SI_CHANNEL_0_OUT:
_uReturnValue = g_Channel[0].m_Out.Hex;
return;
case SI_CHANNEL_0_IN_HI:
g_StatusReg.RDST0 = 0;
UpdateInterrupts();
_uReturnValue = g_Channel[0].m_InHi.Hex;
return;
case SI_CHANNEL_0_IN_LO:
g_StatusReg.RDST0 = 0;
UpdateInterrupts();
_uReturnValue = g_Channel[0].m_InLo.Hex;
return;
//===================================================================================================
// Channel 1
//===================================================================================================
case SI_CHANNEL_1_OUT:
_uReturnValue = g_Channel[1].m_Out.Hex;
return;
case SI_CHANNEL_1_IN_HI:
g_StatusReg.RDST1 = 0;
UpdateInterrupts();
_uReturnValue = g_Channel[1].m_InHi.Hex;
return;
case SI_CHANNEL_1_IN_LO:
g_StatusReg.RDST1 = 0;
UpdateInterrupts();
_uReturnValue = g_Channel[1].m_InLo.Hex;
return;
//===================================================================================================
// Channel 2
//===================================================================================================
case SI_CHANNEL_2_OUT:
_uReturnValue = g_Channel[2].m_Out.Hex;
return;
case SI_CHANNEL_2_IN_HI:
g_StatusReg.RDST2 = 0;
UpdateInterrupts();
_uReturnValue = g_Channel[2].m_InHi.Hex;
return;
case SI_CHANNEL_2_IN_LO:
g_StatusReg.RDST2 = 0;
UpdateInterrupts();
_uReturnValue = g_Channel[2].m_InLo.Hex;
return;
//===================================================================================================
// Channel 3
//===================================================================================================
case SI_CHANNEL_3_OUT:
_uReturnValue = g_Channel[3].m_Out.Hex;
return;
case SI_CHANNEL_3_IN_HI:
g_StatusReg.RDST3 = 0;
UpdateInterrupts();
_uReturnValue = g_Channel[3].m_InHi.Hex;
return;
case SI_CHANNEL_3_IN_LO:
g_StatusReg.RDST3 = 0;
UpdateInterrupts();
_uReturnValue = g_Channel[3].m_InLo.Hex;
return;
case SI_POLL: _uReturnValue = g_Poll.Hex; return;
case SI_COM_CSR: _uReturnValue = g_ComCSR.Hex; return;
case SI_STATUS_REG: _uReturnValue = g_StatusReg.Hex; return;
case SI_EXI_CLOCK_COUNT: _uReturnValue = g_EXIClockCount.Hex; return;
default:
LOG(SERIALINTERFACE, "(r32-unk): 0x%08x", _iAddress);
_dbg_assert_(SERIALINTERFACE,0);
break;
}
// error
_uReturnValue = 0xdeadbeef;
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
LOG(SERIALINTERFACE, "(w32): 0x%08x 0x%08x", _iValue,_iAddress);
// SIBuffer
if ((_iAddress >= 0xCC006480 && _iAddress < 0xCC006500) ||
(_iAddress >= 0xCD006480 && _iAddress < 0xCD006500))
{
*(u32*)&g_SIBuffer[_iAddress & 0x7F] = _iValue;
return;
}
// registers
switch (_iAddress & 0x3FF)
{
case SI_CHANNEL_0_OUT: g_Channel[0].m_Out.Hex = _iValue; break;
case SI_CHANNEL_0_IN_HI: g_Channel[0].m_InHi.Hex = _iValue; break;
case SI_CHANNEL_0_IN_LO: g_Channel[0].m_InLo.Hex = _iValue; break;
case SI_CHANNEL_1_OUT: g_Channel[1].m_Out.Hex = _iValue; break;
case SI_CHANNEL_1_IN_HI: g_Channel[1].m_InHi.Hex = _iValue; break;
case SI_CHANNEL_1_IN_LO: g_Channel[1].m_InLo.Hex = _iValue; break;
case SI_CHANNEL_2_OUT: g_Channel[2].m_Out.Hex = _iValue; break;
case SI_CHANNEL_2_IN_HI: g_Channel[2].m_InHi.Hex = _iValue; break;
case SI_CHANNEL_2_IN_LO: g_Channel[2].m_InLo.Hex = _iValue; break;
case SI_CHANNEL_3_OUT: g_Channel[3].m_Out.Hex = _iValue; break;
case SI_CHANNEL_3_IN_HI: g_Channel[3].m_InHi.Hex = _iValue; break;
case SI_CHANNEL_3_IN_LO: g_Channel[3].m_InLo.Hex = _iValue; break;
case SI_POLL:
g_Poll.Hex = _iValue;
break;
case SI_COM_CSR:
{
USIComCSR tmpComCSR(_iValue);
g_ComCSR.CHANNEL = tmpComCSR.CHANNEL;
g_ComCSR.INLNGTH = tmpComCSR.INLNGTH;
g_ComCSR.OUTLNGTH = tmpComCSR.OUTLNGTH;
g_ComCSR.RDSTINTMSK = tmpComCSR.RDSTINTMSK;
g_ComCSR.TCINTMSK = tmpComCSR.TCINTMSK;
g_ComCSR.COMERR = 0;
if (tmpComCSR.RDSTINT) g_ComCSR.RDSTINT = 0;
if (tmpComCSR.TCINT) g_ComCSR.TCINT = 0;
// be careful: runsi-buffer after updating the INT flags
if (tmpComCSR.TSTART) RunSIBuffer();
UpdateInterrupts();
}
break;
case SI_STATUS_REG:
{
USIStatusReg tmpStatus(_iValue);
// just update the writable bits
g_StatusReg.NOREP0 = tmpStatus.NOREP0 ? 1 : 0;
g_StatusReg.COLL0 = tmpStatus.COLL0 ? 1 : 0;
g_StatusReg.OVRUN0 = tmpStatus.OVRUN0 ? 1 : 0;
g_StatusReg.UNRUN0 = tmpStatus.UNRUN0 ? 1 : 0;
g_StatusReg.NOREP1 = tmpStatus.NOREP1 ? 1 : 0;
g_StatusReg.COLL1 = tmpStatus.COLL1 ? 1 : 0;
g_StatusReg.OVRUN1 = tmpStatus.OVRUN1 ? 1 : 0;
g_StatusReg.UNRUN1 = tmpStatus.UNRUN1 ? 1 : 0;
g_StatusReg.NOREP2 = tmpStatus.NOREP2 ? 1 : 0;
g_StatusReg.COLL2 = tmpStatus.COLL2 ? 1 : 0;
g_StatusReg.OVRUN2 = tmpStatus.OVRUN2 ? 1 : 0;
g_StatusReg.UNRUN2 = tmpStatus.UNRUN2 ? 1 : 0;
g_StatusReg.NOREP3 = tmpStatus.NOREP3 ? 1 : 0;
g_StatusReg.COLL3 = tmpStatus.COLL3 ? 1 : 0;
g_StatusReg.OVRUN3 = tmpStatus.OVRUN3 ? 1 : 0;
g_StatusReg.UNRUN3 = tmpStatus.UNRUN3 ? 1 : 0;
// send command to devices
if (tmpStatus.WR)
{
g_StatusReg.WR = 0;
g_Channel[0].m_pDevice->SendCommand(g_Channel[0].m_Out.Hex);
g_Channel[1].m_pDevice->SendCommand(g_Channel[1].m_Out.Hex);
g_Channel[2].m_pDevice->SendCommand(g_Channel[2].m_Out.Hex);
g_Channel[3].m_pDevice->SendCommand(g_Channel[3].m_Out.Hex);
g_StatusReg.WRST0 = 0;
g_StatusReg.WRST1 = 0;
g_StatusReg.WRST2 = 0;
g_StatusReg.WRST3 = 0;
}
}
break;
case SI_EXI_CLOCK_COUNT:
g_EXIClockCount.Hex = _iValue;
break;
case 0x80:
LOG(SERIALINTERFACE, "WII something at 0xCD006480");
break;
default:
_dbg_assert_(SERIALINTERFACE,0);
break;
}
}
void UpdateInterrupts()
{
// check if we have to update the RDSTINT flag
if (g_StatusReg.RDST0 || g_StatusReg.RDST1 ||
g_StatusReg.RDST2 || g_StatusReg.RDST3)
g_ComCSR.RDSTINT = 1;
else
g_ComCSR.RDSTINT = 0;
// check if we have to generate an interrupt
if ((g_ComCSR.RDSTINT & g_ComCSR.RDSTINTMSK) ||
(g_ComCSR.TCINT & g_ComCSR.TCINTMSK))
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_SI, true);
}
else
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_SI, false);
}
}
void GenerateSIInterrupt(SIInterruptType _SIInterrupt)
{
switch(_SIInterrupt)
{
case INT_RDSTINT: g_ComCSR.RDSTINT = 1; break;
case INT_TCINT: g_ComCSR.TCINT = 1; break;
}
UpdateInterrupts();
}
void UpdateDevices()
{
// update channels
g_StatusReg.RDST0 = g_Channel[0].m_pDevice->GetData(g_Channel[0].m_InHi.Hex, g_Channel[0].m_InLo.Hex) ? 1 : 0;
g_StatusReg.RDST1 = g_Channel[1].m_pDevice->GetData(g_Channel[1].m_InHi.Hex, g_Channel[1].m_InLo.Hex) ? 1 : 0;
g_StatusReg.RDST2 = g_Channel[2].m_pDevice->GetData(g_Channel[2].m_InHi.Hex, g_Channel[2].m_InLo.Hex) ? 1 : 0;
g_StatusReg.RDST3 = g_Channel[3].m_pDevice->GetData(g_Channel[3].m_InHi.Hex, g_Channel[3].m_InLo.Hex) ? 1 : 0;
// update interrupts
UpdateInterrupts();
}
void RunSIBuffer()
{
// math inLength
int inLength = g_ComCSR.INLNGTH;
if (inLength == 0)
inLength = 128;
else
inLength++;
// math outLength
int outLength = g_ComCSR.OUTLNGTH;
if (outLength == 0)
outLength = 128;
else
outLength++;
int numOutput = g_Channel[g_ComCSR.CHANNEL].m_pDevice->RunBuffer(g_SIBuffer, inLength);
LOG(SERIALINTERFACE, "RunSIBuffer (intLen: %i outLen: %i) (processed: %i)", inLength, outLength, numOutput);
// Transfer completed
GenerateSIInterrupt(INT_TCINT);
g_ComCSR.TSTART = 0;
}
} // end of namespace SerialInterface

View File

@ -0,0 +1,43 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _SERIALINTERFACE_H
#define _SERIALINTERFACE_H
#include "Common.h"
namespace SerialInterface
{
// Init
void Init();
// Shutdown
void Shutdown();
void UpdateDevices();
// Read32
void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
// Write32
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
}; // end of namespace SerialInterface
#endif

View File

@ -0,0 +1,233 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <stdio.h>
#include <stdlib.h>
#include "SerialInterface_Devices.h"
#include "../Plugins/Plugin_PAD.h"
#include "../PowerPC/PowerPC.h"
#include "CPU.h"
#define SI_TYPE_GC 0x08000000u
#define SI_GC_STANDARD 0x01000000u // dolphin standard controller
#define SI_GC_NOMOTOR 0x20000000u // no rumble motor
#define SI_GC_KEYBOARD (SI_TYPE_GC | 0x00200000)
#define SI_GC_CONTROLLER (SI_TYPE_GC | SI_GC_STANDARD)
#define SI_MAX_COMCSR_INLNGTH 128
#define SI_MAX_COMCSR_OUTLNGTH 128
// =====================================================================================================
// --- base class ---
// =====================================================================================================
int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength)
{
#ifdef _DEBUG
LOG(SERIALINTERFACE, "Send Data Device(%i) - Length(%i) ", ISIDevice::m_iDeviceNumber,_iLength);
char szTemp[256] = "";
int num = 0;
while(num < _iLength)
{
char szTemp2[128] = "";
sprintf(szTemp2, "0x%02x ", _pBuffer[num^3]);
strcat(szTemp, szTemp2);
num++;
if ((num % 8) == 0)
{
LOG(SERIALINTERFACE, szTemp);
szTemp[0] = '\0';
}
}
LOG(SERIALINTERFACE, szTemp);
#endif
return 0;
};
// =====================================================================================================
// --- standard gamecube controller ---
// =====================================================================================================
CSIDevice_GCController::CSIDevice_GCController(int _iDeviceNumber) :
ISIDevice(_iDeviceNumber)
{
memset(&m_origin, 0, sizeof(SOrigin));
m_origin.uCommand = 0x41;
m_origin.uOriginStickX = 0x80;
m_origin.uOriginStickY = 0x80;
m_origin.uSubStickStickX = 0x80;
m_origin.uSubStickStickY = 0x80;
m_origin.uTrigger_L = 0x1F;
m_origin.uTrigger_R = 0x1F;
}
int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength)
{
// for debug logging only
ISIDevice::RunBuffer(_pBuffer, _iLength);
int iPosition = 0;
while(iPosition < _iLength)
{
// read the command
EBufferCommands command = static_cast<EBufferCommands>(_pBuffer[iPosition ^ 3]);
iPosition ++;
// handle it
switch(command)
{
case CMD_RESET:
{
*(u32*)&_pBuffer[0] = SI_GC_CONTROLLER; // | SI_GC_NOMOTOR;
iPosition = _iLength; // break the while loop
}
break;
case CMD_ORIGIN:
{
LOG(SERIALINTERFACE, "SI - Get Origin");
u8* pCalibration = reinterpret_cast<u8*>(&m_origin);
for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
_pBuffer[i ^ 3] = *pCalibration++;
}
}
iPosition = _iLength;
break;
// Recalibrate (FiRES: i am not 100 percent sure about this)
case CMD_RECALIBRATE:
{
LOG(SERIALINTERFACE, "SI - Recalibrate");
u8* pCalibration = reinterpret_cast<u8*>(&m_origin);
for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
_pBuffer[i ^ 3] = *pCalibration++;
}
}
iPosition = _iLength;
break;
// WII Something
case 0xCE:
LOG(SERIALINTERFACE, "Unknown Wii SI Command");
break;
// DEFAULT
default:
{
LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command);
PanicAlert("SI: Unknown command");
iPosition = _iLength;
}
break;
}
}
return iPosition;
}
// __________________________________________________________________________________________________
// GetData
//
// return true on new data (max 7 Bytes and 6 bits ;)
//
bool
CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
{
SPADStatus PadStatus;
memset(&PadStatus, 0 ,sizeof(PadStatus));
PluginPAD::PAD_GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
_Hi = (u32)((u8)PadStatus.stickY);
_Hi |= (u32)((u8)PadStatus.stickX << 8);
_Hi |= (u32)((u16)PadStatus.button << 16);
_Low = (u8)PadStatus.triggerRight;
_Low |= (u32)((u8)PadStatus.triggerLeft << 8);
_Low |= (u32)((u8)PadStatus.substickY << 16);
_Low |= (u32)((u8)PadStatus.substickX << 24);
// F|RES:
// i dunno if i should force it here
// means that the pad must be "combined" with the origin to math the "final" OSPad-Struct
_Hi |= 0x00800000;
return true;
}
// __________________________________________________________________________________________________
// SendCommand
//
void
CSIDevice_GCController::SendCommand(u32 _Cmd)
{
UCommand command(_Cmd);
switch(command.Command)
{
// Costis sent it in some demos :)
case 0x00:
break;
case CMD_RUMBLE:
{
unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard
unsigned int uStrength = command.Parameter2;
PluginPAD::PAD_Rumble(ISIDevice::m_iDeviceNumber, uType, uStrength);
}
break;
default:
{
LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd);
PanicAlert("SI: Unknown direct command");
}
break;
}
}
// =====================================================================================================
// --- dummy device ---
// =====================================================================================================
CSIDevice_Dummy::CSIDevice_Dummy(int _iDeviceNumber) :
ISIDevice(_iDeviceNumber)
{}
int CSIDevice_Dummy::RunBuffer(u8* _pBuffer, int _iLength)
{
reinterpret_cast<u32*>(_pBuffer)[0] = 0x00000000; // no device
return 4;
}
bool CSIDevice_Dummy::GetData(u32& _Hi, u32& _Low)
{
return false;
}
void CSIDevice_Dummy::SendCommand(u32 _Cmd)
{
}

View File

@ -0,0 +1,137 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _SERIALINTERFACE_DEVICES_H
#define _SERIALINTERFACE_DEVICES_H
#include "Common.h"
class ISIDevice
{
protected:
int m_iDeviceNumber;
public:
// constructor
ISIDevice(int _iDeviceNumber) :
m_iDeviceNumber(_iDeviceNumber)
{ }
virtual ~ISIDevice() { }
// run the SI Buffer
virtual int RunBuffer(u8* _pBuffer, int _iLength);
// return true on new data
virtual bool GetData(u32& _Hi, u32& _Low) = 0;
// send a command directly (no detour per buffer)
virtual void SendCommand(u32 _Cmd) = 0;
};
// =====================================================================================================
// standard gamecube controller
// =====================================================================================================
class CSIDevice_GCController : public ISIDevice
{
private:
// commands
enum EBufferCommands
{
CMD_INVALID = 0xFFFFFFFF,
CMD_RESET = 0x00,
CMD_ORIGIN = 0x41,
CMD_RECALIBRATE = 0x42,
};
struct SOrigin
{
u8 uCommand;
u8 unk_1;
u8 uOriginStickX;
u8 uOriginStickY;
u8 uSubStickStickX; // ???
u8 uSubStickStickY; // ???
u8 uTrigger_L; // ???
u8 uTrigger_R; // ???
u8 unk_4;
u8 unk_5;
u8 unk_6;
u8 unk_7;
};
enum EDirectCommands
{
CMD_RUMBLE = 0x40
};
union UCommand
{
u32 Hex;
struct
{
unsigned Parameter1 : 8;
unsigned Parameter2 : 8;
unsigned Command : 8;
unsigned : 8;
};
UCommand() {Hex = 0;}
UCommand(u32 _iValue) {Hex = _iValue;}
};
SOrigin m_origin;
public:
// constructor
CSIDevice_GCController(int _iDeviceNumber);
// run the SI Buffer
virtual int RunBuffer(u8* _pBuffer, int _iLength);
// return true on new data
virtual bool GetData(u32& _Hi, u32& _Low);
// send a command directly
virtual void SendCommand(u32 _Cmd);
};
// =====================================================================================================
// dummy - no device attached
// =====================================================================================================
class CSIDevice_Dummy : public ISIDevice
{
public:
// constructor
CSIDevice_Dummy(int _iDeviceNumber);
// run the SI Buffer
virtual int RunBuffer(u8* _pBuffer, int _iLength);
// return true on new data
virtual bool GetData(u32& _Hi, u32& _Low);
// send a command directly
virtual void SendCommand(u32 _Cmd);
};
#endif

View File

@ -0,0 +1,32 @@
/*********************************************************************
Nintendo GameCube ADPCM Decoder Core Class
Original Author: Shinji Chiba <ch3@mail.goo.ne.jp>
Modified to fit Dolphin code style by ector
History: Mar.19 2001 - Create.
*********************************************************************/
#ifndef _STREAMADPCM_H
#define _STREAMADPCM_H
#include "Common.h"
#define ONE_BLOCK_SIZE 32
#define SAMPLES_PER_BLOCK 28
#define MONO 1
#define STEREO 2
class NGCADPCM
{
public:
static void InitFilter();
static void DecodeBlock( short*pcm, u8 *adpcm);
private:
static float iir1[STEREO], iir2[STEREO];
static short DecodeSample(int, int, int);
};
#endif

View File

@ -0,0 +1,59 @@
/*********************************************************************
Nintendo GameCube ADPCM Decoder Core Class
Author: Shinji Chiba <ch3@mail.goo.ne.jp>
*********************************************************************/
#include "StreamADPCM.H"
float NGCADPCM::iir1[STEREO], NGCADPCM::iir2[STEREO];
void NGCADPCM::InitFilter()
{
iir1[0] = iir1[1] =
iir2[0] = iir2[1] = 0.0f;
}
short NGCADPCM::DecodeSample( int bits, int q, int ch )
{
static const float coef[4] = { 0.86f, 1.8f, 0.82f, 1.53f };
float iir_filter;
iir_filter = (float) ((short) (bits << 12) >> (q & 0xf));
switch (q >> 4)
{
case 1:
iir_filter += (iir1[ch] * coef[0]);
break;
case 2:
iir_filter += (iir1[ch] * coef[1] - iir2[ch] * coef[2]);
break;
case 3:
iir_filter += (iir1[ch] * coef[3] - iir2[ch] * coef[0]);
}
iir2[ch] = iir1[ch];
if ( iir_filter <= -32768.5f )
{
iir1[ch] = -32767.5f;
return -32767;
}
else if ( iir_filter >= 32767.5f )
{
iir1[ch] = 32767.5f;
return 32767;
}
return (short) ((iir1[ch] = iir_filter) * 0.5f);
}
void NGCADPCM::DecodeBlock( short *pcm, u8* adpcm)
{
int ch = 1;
int 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 + MONO] = DecodeSample( adpcm[i + (ONE_BLOCK_SIZE - SAMPLES_PER_BLOCK)] >> 4, adpcm[ch], ch );
}
}

View File

@ -0,0 +1,232 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "../PatchEngine.h"
#include "SystemTimers.h"
#include "../Plugins/Plugin_DSP.h"
#include "../Plugins/Plugin_Video.h"
#include "../HW/DSP.h"
#include "../HW/AudioInterface.h"
#include "../HW/VideoInterface.h"
#include "../HW/SerialInterface.h"
#include "../PowerPC/PowerPC.h"
#include "../CoreTiming.h"
#include "../Core.h"
#include "../IPC_HLE/WII_IPC_HLE.h"
#include "Thread.h"
#include "Timer.H"
namespace SystemTimers
{
u32 CPU_CORE_CLOCK = 486000000u; // 486 mhz (its not 485, stop bugging me!)
const int ThrottleFrequency = 60;
s64 fakeDec;
//ratio of TB and Decrementer to clock cycles
//4 or 8? not really sure, but think it's 8
enum {
TIMER_RATIO = 8
};
// These are badly educated guesses
// Feel free to experiment
int
// 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
// VideoInterface::Update is stupid!
VI_PERIOD = GetTicksPerSecond() / (60*120),
SI_PERIOD = GetTicksPerSecond() / 60, //once a frame is good for controllers
// These are the big question marks IMHO :)
AI_PERIOD = GetTicksPerSecond() / 80,
DSP_PERIOD = GetTicksPerSecond() / 250,
DSPINT_PERIOD = GetTicksPerSecond() / 230,
HLE_IPC_PERIOD = GetTicksPerSecond() / 250;
u32 GetTicksPerSecond()
{
return CPU_CORE_CLOCK;
}
u32 ConvertMillisecondsToTicks(u32 _Milliseconds)
{
return GetTicksPerSecond() / 1000 * _Milliseconds;
}
void AICallback(u64 userdata, int cyclesLate)
{
AudioInterface::Update();
CoreTiming::ScheduleEvent(AI_PERIOD-cyclesLate, &AICallback, "AICallback");
}
void IPC_HLE_UpdateCallback(u64 userdata, int cyclesLate)
{
WII_IPC_HLE_Interface::Update();
CoreTiming::ScheduleEvent(HLE_IPC_PERIOD-cyclesLate, &IPC_HLE_UpdateCallback, "IPC_HLE_UpdateCallback");
}
void VICallback(u64 userdata, int cyclesLate)
{
VideoInterface::Update();
CoreTiming::ScheduleEvent(VI_PERIOD-cyclesLate, &VICallback, "VICallback");
}
void SICallback(u64 userdata, int cyclesLate)
{
// This is once per frame - good candidate for patching stuff
PatchEngine_ApplyFramePatches();
// OK, do what we are here to do.
SerialInterface::UpdateDevices();
CoreTiming::ScheduleEvent(SI_PERIOD-cyclesLate, &SICallback, "SICallback");
}
void DSPCallback(u64 userdata, int cyclesLate)
{
PluginDSP::DSP_Update();
CoreTiming::ScheduleEvent(DSP_PERIOD-cyclesLate, &DSPCallback, "DSPCallback");
}
void DSPInterruptCallback(u64 userdata, int cyclesLate)
{
DSP::GenerateDSPInterrupt(DSP::INT_AI);
CoreTiming::ScheduleEvent(DSPINT_PERIOD-cyclesLate, &DSPInterruptCallback, "DSPInterruptCallback");
}
void DecrementerCallback(u64 userdata, int cyclesLate)
{
//Why is fakeDec too big here?
fakeDec = -1;
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
}
void DecrementerSet()
{
// MessageBox(0, "dec set",0,0);
u32 decValue = PowerPC::ppcState.spr[SPR_DEC];
fakeDec = decValue*TIMER_RATIO;
CoreTiming::RemoveEvent(DecrementerCallback);
CoreTiming::ScheduleEvent(decValue*TIMER_RATIO, DecrementerCallback, "DecCallback");
}
void AdvanceCallback(int cyclesExecuted)
{
//int oldFakeDec = fakeDec;
fakeDec -= cyclesExecuted;
//if (fakeDec < 0 && oldFakeDec > 0)
// fakeDec = TIMER_RATIO;
u64 timebase_ticks = CoreTiming::GetTicks() / TIMER_RATIO; //works since we are little endian and TL comes first :)
*(u64*)&TL = timebase_ticks;
if (fakeDec >= 0)
PowerPC::ppcState.spr[SPR_DEC] = (u32)fakeDec / TIMER_RATIO;
}
// TODO(ector): improve, by using a more accurate timer
// calculate the timing over the past 7 frames
// calculating over all time doesn't work : if it's slow for a while, will run like crazy after that
// calculating over just 1 frame is too shaky
#define HISTORYLENGTH 7
int timeHistory[HISTORYLENGTH] = {0,0,0,0,0};
void Throttle(u64 userdata, int cyclesLate)
{
return;
static Common::Timer timer;
for (int i=0; i<HISTORYLENGTH-1; i++)
timeHistory[i] = timeHistory[i+1];
int t = (int)timer.GetTimeDifference();
//timer.Update();
if (timeHistory[0] != 0)
{
const int delta = (int)(1000*(HISTORYLENGTH-1)/ThrottleFrequency);
while (t - timeHistory[0] < delta)
{
// ugh, busy wait
Common::SleepCurrentThread(0);
t = (int)timer.GetTimeDifference();
}
}
timeHistory[HISTORYLENGTH-1] = t;
CoreTiming::ScheduleEvent((int)(GetTicksPerSecond()/ThrottleFrequency)-cyclesLate, &Throttle, "Throttle");
}
void Init()
{
if (Core::GetStartupParameter().bWii)
{
CPU_CORE_CLOCK = 721000000;
VI_PERIOD = GetTicksPerSecond() / (60*120),
SI_PERIOD = GetTicksPerSecond() / 60, //once a frame is good for controllers
// These are the big question marks IMHO :)
AI_PERIOD = GetTicksPerSecond() / 80,
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.003f),
DSPINT_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
HLE_IPC_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
}
else
{
CPU_CORE_CLOCK = 486000000;
VI_PERIOD = GetTicksPerSecond() / (60*120),
SI_PERIOD = GetTicksPerSecond() / 60, //once a frame is good for controllers
// These are the big question marks IMHO :)
AI_PERIOD = GetTicksPerSecond() / 80,
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.005f),
DSPINT_PERIOD = (int)(GetTicksPerSecond() *0.005f);
}
Common::Timer::IncreaseResolution();
memset(timeHistory, 0, sizeof(timeHistory));
CoreTiming::Clear();
if (Core::GetStartupParameter().bThrottle) {
CoreTiming::ScheduleEvent((int)(GetTicksPerSecond()/ThrottleFrequency), &Throttle, "Throttle");
}
CoreTiming::ScheduleEvent(AI_PERIOD, &AICallback, "AICallback");
CoreTiming::ScheduleEvent(VI_PERIOD, &VICallback, "VICallback");
CoreTiming::ScheduleEvent(DSP_PERIOD, &DSPCallback, "DSPCallback");
CoreTiming::ScheduleEvent(SI_PERIOD, &SICallback, "SICallback");
CoreTiming::ScheduleEvent(DSPINT_PERIOD, &DSPInterruptCallback, "DSPInterruptCallback");
if (Core::GetStartupParameter().bWii)
{
CoreTiming::ScheduleEvent(HLE_IPC_PERIOD, &IPC_HLE_UpdateCallback, "IPC_HLE_UpdateCallback");
}
CoreTiming::RegisterAdvanceCallback(&AdvanceCallback);
}
void Shutdown()
{
Common::Timer::RestoreResolution();
CoreTiming::Clear();
}
}

View File

@ -0,0 +1,35 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _SYSTEMTIMERS_H
#define _SYSTEMTIMERS_H
#include "Common.h"
namespace SystemTimers
{
u32 GetTicksPerSecond();
void Init();
void Shutdown();
// Notify timing system that somebody wrote to the decrementer
void DecrementerSet();
}
#endif

View File

@ -0,0 +1,398 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../PowerPC/PowerPC.h"
#include "PeripheralInterface.h"
#include "VideoInterface.h"
#include "Memmap.h"
#include "../Plugins/Plugin_Video.h"
#include "../CoreTiming.h"
#include "../HW/SystemTimers.h"
namespace VideoInterface
{
// VI Internal Hardware Addresses
enum
{
VI_CONTROL_REGISTER = 0x02,
VI_FRAMEBUFFER_1 = 0x01C,
VI_FRAMEBUFFER_2 = 0x024,
VI_VERTICAL_BEAM_POSITION = 0x02C,
VI_HORIZONTAL_BEAM_POSITION = 0x02e,
VI_PRERETRACE = 0x030,
VI_POSTRETRACE = 0x034,
VI_DI2 = 0x038,
VI_DI3 = 0x03C,
VI_INTERLACE = 0x850,
VI_HSCALEW = 0x04A,
VI_HSCALER = 0x04C,
};
union UVIDisplayControlRegister
{
u16 Hex;
struct
{
unsigned ENB : 1;
unsigned RST : 1;
unsigned NIN : 1;
unsigned DLR : 1;
unsigned LE0 : 2;
unsigned LE1 : 2;
unsigned FMT : 2;
unsigned : 6;
};
UVIDisplayControlRegister(u16 _hex) { Hex = _hex;}
UVIDisplayControlRegister() { Hex = 0;}
};
// VI Interrupt Register
union UVIInterruptRegister
{
u32 Hex;
struct
{
u16 Lo;
u16 Hi;
};
struct
{
unsigned HCT : 11;
unsigned : 5;
unsigned VCT : 11;
unsigned : 1;
unsigned IR_MASK : 1;
unsigned : 2;
unsigned IR_INT : 1;
};
};
UVIDisplayControlRegister m_VIDisplayControlRegister;
// Framebuffers
u32 m_FrameBuffer1; // normal framebuffer address
u32 m_FrameBuffer2; // framebuffer for 3d buffer address
// VI Interrupt Registers
UVIInterruptRegister m_VIInterruptRegister[4];
u8 m_UVIUnknownRegs[0x1000];
u16 HorizontalBeamPos = 0;
u16 VerticalBeamPos = 0;
u32 TicksPerFrame = 0;
u32 LineCount = 0;
u64 LastTime = 0;
void Init()
{
for (int i=0; i<4; i++)
{
m_VIInterruptRegister[i].Hex = 0x00;
}
m_VIDisplayControlRegister.Hex = 0x0000;
m_VIDisplayControlRegister.ENB = 0;
m_VIDisplayControlRegister.FMT = 0;
}
void Read16(u16& _uReturnValue, const u32 _iAddress)
{
switch (_iAddress & 0xFFF)
{
case VI_CONTROL_REGISTER:
LOG(VIDEOINTERFACE, "VideoInterface(r16): VI_CONTROL_REGISTER 0x%08x", m_VIDisplayControlRegister.Hex);
_uReturnValue = m_VIDisplayControlRegister.Hex;
return;
case VI_VERTICAL_BEAM_POSITION:
_uReturnValue = VerticalBeamPos;
return;
case VI_HORIZONTAL_BEAM_POSITION:
_uReturnValue = HorizontalBeamPos;
return;
// RETRACE STUFF ...
case VI_PRERETRACE:
_uReturnValue = m_VIInterruptRegister[0].Hi;
return;
case VI_POSTRETRACE:
_uReturnValue = m_VIInterruptRegister[1].Hi;
return;
case 0x38:
_uReturnValue = m_VIInterruptRegister[2].Hi;
return;
case 0x3C:
_uReturnValue = m_VIInterruptRegister[3].Hi;
return;
default:
_uReturnValue = *(u16*)&m_UVIUnknownRegs[_iAddress & 0xFFF];
return;
}
_uReturnValue = 0x0;
}
void Write16(const u16 _iValue, const u32 _iAddress)
{
LOG(VIDEOINTERFACE, "(w16): 0x%04x, 0x%08x",_iValue,_iAddress);
//Somewhere it sets screen width.. we need to communicate this to the gfx plugin...
switch (_iAddress & 0xFFF)
{
case VI_CONTROL_REGISTER:
{
UVIDisplayControlRegister tmpConfig(_iValue);
m_VIDisplayControlRegister.ENB = tmpConfig.ENB;
m_VIDisplayControlRegister.NIN = tmpConfig.NIN;
m_VIDisplayControlRegister.DLR = tmpConfig.DLR;
m_VIDisplayControlRegister.LE0 = tmpConfig.LE0;
m_VIDisplayControlRegister.LE1 = tmpConfig.LE1;
m_VIDisplayControlRegister.FMT = tmpConfig.FMT;
if (tmpConfig.RST)
{
m_VIDisplayControlRegister.RST = 0;
}
UpdateTiming();
}
break;
case VI_VERTICAL_BEAM_POSITION:
_dbg_assert_(VIDEOINTERFACE,0);
break;
case VI_HORIZONTAL_BEAM_POSITION:
_dbg_assert_(VIDEOINTERFACE,0);
break;
// RETRACE STUFF ...
case VI_PRERETRACE:
m_VIInterruptRegister[0].Hi = _iValue;
UpdateInterrupts();
break;
case VI_POSTRETRACE:
m_VIInterruptRegister[1].Hi = _iValue;
UpdateInterrupts();
break;
case VI_DI2:
m_VIInterruptRegister[2].Hi = _iValue;
UpdateInterrupts();
break;
case VI_DI3:
m_VIInterruptRegister[3].Hi = _iValue;
UpdateInterrupts();
break;
case VI_HSCALEW:
{
// int width = _iValue&0x3FF;
}
break;
case VI_HSCALER:
{
// int hsEnable = (_iValue&(1<<12)) ? true : false;
}
break;
default:
*(u16*)&m_UVIUnknownRegs[_iAddress & 0xFFF] = _iValue;
break;
}
}
void Read32(u32& _uReturnValue, const u32 _iAddress)
{
LOG(VIDEOINTERFACE, "(r32): 0x%08x", _iAddress);
if ((_iAddress & 0xFFF) < 0x20)
{
_uReturnValue = 0;
return;
}
switch (_iAddress & 0xFFF)
{
case 0x000:
case 0x004:
case 0x008:
case 0x00C:
_uReturnValue = 0; //FL
return;
default:
//_assert_(0);
_uReturnValue = 0xAFFE;
return;
}
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
LOG(VIDEOINTERFACE, "(w32): 0x%08x, 0x%08x",_iValue,_iAddress);
switch(_iAddress & 0xFFF)
{
case VI_FRAMEBUFFER_1:
m_FrameBuffer1 = _iValue;
break;
case VI_FRAMEBUFFER_2:
m_FrameBuffer2 = _iValue;
break;
default:
PanicAlert("VI unknown write32 %08x to %08x", _iValue, _iAddress);
break;
}
}
void UpdateInterrupts()
{
if ((m_VIInterruptRegister[0].IR_INT & m_VIInterruptRegister[0].IR_MASK) ||
(m_VIInterruptRegister[1].IR_INT & m_VIInterruptRegister[1].IR_MASK) ||
(m_VIInterruptRegister[2].IR_INT & m_VIInterruptRegister[2].IR_MASK) ||
(m_VIInterruptRegister[3].IR_INT & m_VIInterruptRegister[3].IR_MASK))
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_VI, true);
}
else
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_VI, false);
}
}
void GenerateVIInterrupt(VIInterruptType _VIInterrupt)
{
switch(_VIInterrupt)
{
case INT_PRERETRACE: m_VIInterruptRegister[0].IR_INT = 1; break;
case INT_POSTRETRACE: m_VIInterruptRegister[1].IR_INT = 1; break;
case INT_REG_2: m_VIInterruptRegister[2].IR_INT = 1; break;
case INT_REG_3: m_VIInterruptRegister[3].IR_INT = 1; break;
}
UpdateInterrupts();
// debug check
if ((m_VIInterruptRegister[2].IR_MASK == 1) ||
(m_VIInterruptRegister[3].IR_MASK == 1))
{
PanicAlert("m_VIInterruptRegister[2 and 3] activated - Tell F|RES :)");
}
}
u8* GetFrameBufferPointer()
{
return Memory::GetPointer(VideoInterface::m_FrameBuffer1);
}
void PreInit(bool _bNTSC)
{
TicksPerFrame = 0;
LineCount = 0;
LastTime = 0;
Write16(0x4769, 0xcc002004);
Write16(0x01ad, 0xcc002006);
Write16(0x5140, 0xcc00200a);
Write16(0x02ea, 0xcc002008);
Write16(0x0006, 0xcc002000);
Write16(0x01f6, 0xcc00200e);
Write16(0x0005, 0xcc00200c);
Write16(0x01f7, 0xcc002012);
Write16(0x0004, 0xcc002010);
Write16(0x410c, 0xcc002016);
Write16(0x410c, 0xcc002014);
Write16(0x40ed, 0xcc00201a);
Write16(0x40ed, 0xcc002018);
Write16(0x2828, 0xcc002048);
Write16(0x0001, 0xcc002036);
Write16(0x1001, 0xcc002034);
Write16(0x01ae, 0xcc002032);
Write16(0x1107, 0xcc002030);
Write16(0x0000, 0xcc00206c);
if (_bNTSC)
Write16(0x0001, 0xcc002002); // STATUS REG
else
Write16(0x0101, 0xcc002002); // STATUS REG
}
void UpdateTiming()
{
switch (m_VIDisplayControlRegister.FMT)
{
case 0:
case 2:
TicksPerFrame = SystemTimers::GetTicksPerSecond() / 30;
LineCount = m_VIDisplayControlRegister.NIN ? 263 : 525;
break;
case 1:
TicksPerFrame = SystemTimers::GetTicksPerSecond() / 25;
LineCount = m_VIDisplayControlRegister.NIN ? 313 : 625;
break;
default:
PanicAlert("Unknown Video Format - CVideoInterface");
break;
}
}
void Update()
{
// This stuff is not right - what if more than TicksPerLine ticks occur between
// calls to this function, say if we run with fairly inaccurate timing?
while ((CoreTiming::GetTicks() - LastTime) > (TicksPerFrame / LineCount))
{
LastTime += (TicksPerFrame / LineCount);
//
VerticalBeamPos++;
if (VerticalBeamPos > LineCount)
{
VerticalBeamPos = 1;
}
// check INT_PRERETRACE
if (m_VIInterruptRegister[0].VCT == VerticalBeamPos)
{
m_VIInterruptRegister[0].IR_INT = 1;
UpdateInterrupts();
}
// INT_POSTRETRACE
if (m_VIInterruptRegister[1].VCT == VerticalBeamPos)
{
m_VIInterruptRegister[1].IR_INT = 1;
UpdateInterrupts();
}
}
}
}

View File

@ -0,0 +1,68 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _VIDEOINTERFACE_H
#define _VIDEOINTERFACE_H
#include "Common.h"
namespace VideoInterface
{
enum VIInterruptType
{
INT_PRERETRACE = 0,
INT_POSTRETRACE = 1,
INT_REG_2,
INT_REG_3,
};
// Init
void Init();
// Read
void HWCALL Read16(u16& _uReturnValue, const u32 _uAddress);
void HWCALL Read32(u32& _uReturnValue, const u32 _uAddress);
// Write
void HWCALL Write16(const u16 _uValue, const u32 _uAddress);
void HWCALL Write32(const u32 _uValue, const u32 _uAddress);
void GenerateVIInterrupt(VIInterruptType _VIInterrupt);
// returns a pointer to the framebuffer
u8* GetFrameBufferPointer();
// pre init
void PreInit(bool _bNTSC);
// VI Unknown Regs
extern u8 m_UVIUnknownRegs[0x1000];
// ??????
void Update();
// UpdateInterrupts: check if we have to generate a new VI Interrupt
void UpdateInterrupts();
// ??????
void UpdateTiming();
};
#endif

View File

@ -0,0 +1,133 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "WII_IOB.h"
namespace WII_IOBridge
{
void HWCALL Read8(u8& _rReturnValue, const u32 _Address)
{
_dbg_assert_(WII_IOB,0);
}
void HWCALL Read16(u16& _rReturnValue, const u32 _Address)
{
_dbg_assert_(WII_IOB,0);
}
void HWCALL Read32(u32& _rReturnValue, const u32 _Address)
{
switch(_Address & 0xFFFF)
{
case 0xc0: // __VISendI2CData
_rReturnValue = 0;
LOG(WII_IOB, "IOP: Read32 from 0xc0 = 0x%08x (__VISendI2CData)", _rReturnValue);
break;
case 0xc4: // __VISendI2CData
_rReturnValue = 0;
LOG(WII_IOB, "IOP: Read32 from 0xc4 = 0x%08x (__VISendI2CData)", _rReturnValue);
break;
case 0xc8: // __VISendI2CData
_rReturnValue = 0;
LOG(WII_IOB, "IOP: Read32 from 0xc8 = 0x%08x (__VISendI2CData)", _rReturnValue);
break;
case 0x180: // __AIClockInit
_rReturnValue = 0;
LOG(WII_IOB, "IOP: Read32 from 0x180 = 0x%08x (__AIClockInit)", _rReturnValue);
return;
case 0x1CC: // __AIClockInit
_rReturnValue = 0;
LOG(WII_IOB, "IOP: Read32 from 0x1CC = 0x%08x (__AIClockInit)", _rReturnValue);
return;
case 0x1D0: // __AIClockInit
_rReturnValue = 0;
LOG(WII_IOB, "IOP: Read32 from 0x1D0 = 0x%08x (__AIClockInit)", _rReturnValue);
return;
default:
_dbg_assert_msg_(WII_IOB, 0, "IOP: Read32 from 0x%08x", _Address);
break;
}
}
void HWCALL Read64(u64& _rReturnValue, const u32 _Address)
{
_dbg_assert_(WII_IOB,0);
}
void HWCALL Write8(const u8 _Value, const u32 _Address)
{
_dbg_assert_(WII_IOB,0);
}
void HWCALL Write16(const u16 _Value, const u32 _Address)
{
_dbg_assert_(WII_IOB,0);
}
void HWCALL Write32(const u32 _Value, const u32 _Address)
{
switch(_Address & 0xFFFF)
{
case 0xc0: // __VISendI2CData
LOG(WII_IOB, "IOP: Write32 to 0xc0 = 0x%08x (__VISendI2CData)", _Value);
break;
case 0xc4: // __VISendI2CData
LOG(WII_IOB, "IOP: Write32 to 0xc4 = 0x%08x (__VISendI2CData)", _Value);
break;
case 0xc8: // __VISendI2CData
LOG(WII_IOB, "IOP: Write32 to 0xc8 = 0x%08x (__VISendI2CData)", _Value);
break;
case 0x180: // __AIClockInit
LOG(WII_IOB, "IOP: Write32 to 0x180 = 0x%08x (__AIClockInit)", _Value);
return;
case 0x1CC: // __AIClockInit
LOG(WII_IOB, "IOP: Write32 to 0x1D0 = 0x%08x (__AIClockInit)", _Value);
return;
case 0x1D0: // __AIClockInit
LOG(WII_IOB, "IOP: Write32 to 0x1D0 = 0x%08x (__AIClockInit)", _Value);
return;
default:
_dbg_assert_msg_(WII_IOB, 0, "IOP: Write32 to 0x%08x", _Address);
break;
}
}
void HWCALL Write64(const u64 _Value, const u32 _Address)
{
switch(_Address)
{
default:
_dbg_assert_msg_(WII_IOB, 0, "IOP: Write32 to 0x%08x", _Address);
break;
}
}
} // end of namespace AudioInterfac

View File

@ -0,0 +1,45 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WII_IOBRIDGE_H_
#define _WII_IOBRIDGE_H_
namespace WII_IOBridge
{
// Init
void Init();
// Shutdown
void Shutdown();
// Update
void Update();
void HWCALL Read8(u8& _rReturnValue, const u32 _Address);
void HWCALL Read16(u16& _rReturnValue, const u32 _Address);
void HWCALL Read32(u32& _rReturnValue, const u32 _Address);
void HWCALL Read64(u64& _rReturnValue, const u32 _Address);
void HWCALL Write8(const u8 _Value, const u32 _Address);
void HWCALL Write16(const u16 _Value, const u32 _Address);
void HWCALL Write32(const u32 _Value, const u32 _Address);
void HWCALL Write64(const u64 _Value, const u32 _Address);
} // end of namespace AudioInterface
#endif

View File

@ -0,0 +1,250 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <map>
#include "Common.h"
#include "WII_IPC.h"
#include "CPU.h"
#include "Memmap.h"
#include "PeripheralInterface.h"
#include "../IPC_HLE/WII_IPC_HLE.h"
namespace WII_IPCInterface
{
enum
{
IPC_COMMAND_REGISTER = 0x00,
IPC_CONTROL_REGISTER = 0x04,
IPC_REPLY_REGISTER = 0x08,
IPC_STATUS_REGISTER = 0x30,
IPC_CONFIG_REGISTER = 0x34,
IPC_SENSOR_BAR_POWER_REGISTER = 0xC0
};
union UIPC_Control
{
u32 Hex;
struct
{
unsigned ExecuteCmd : 1;
unsigned AckReady : 1;
unsigned ReplyReady : 1;
unsigned Relaunch : 1;
unsigned unk5 : 1;
unsigned unk6 : 1;
unsigned pad : 26;
};
UIPC_Control(u32 _Hex = 0) {Hex = _Hex;}
};
union UIPC_Status
{
u32 Hex;
struct
{
unsigned : 30;
unsigned INTERRUPT : 1; // 0x40000000
unsigned : 1;
};
UIPC_Status(u32 _Hex = 0) {Hex = _Hex;}
};
union UIPC_Config
{
u32 Hex;
struct
{
unsigned : 30;
unsigned INT_MASK : 1; // 0x40000000
unsigned : 1;
};
UIPC_Config(u32 _Hex = 0)
{
Hex = _Hex;
INT_MASK = 1;
}
};
UIPC_Status g_IPC_Status;
UIPC_Config g_IPC_Config;
UIPC_Control g_IPC_Control;
u32 g_Address = 0;
u32 g_Reply = 0;
u32 g_SensorBarPower = 0;
void UpdateInterrupts();
// Init
void Init()
{
g_Address = 0;
g_Reply = 0;
g_SensorBarPower = 0;
g_IPC_Status = UIPC_Status();
g_IPC_Config = UIPC_Config();
g_IPC_Control = UIPC_Control();
}
void Shutdown()
{
}
void HWCALL Read32(u32& _rReturnValue, const u32 _Address)
{
switch(_Address & 0xFFFF)
{
case IPC_CONTROL_REGISTER:
_rReturnValue = g_IPC_Control.Hex;
LOG(WII_IPC, "IOP: Read32 from IPC_CONTROL_REGISTER(0x04) = 0x%08x", _rReturnValue);
// CCPU::Break();
// if ((REASON_REG & 0x14) == 0x14) CALL IPCReplayHanlder
// if ((REASON_REG & 0x22) != 0x22) Jumps to the end
break;
case IPC_REPLY_REGISTER: // looks a little bit like a callback function
_rReturnValue = g_Reply;
LOG(WII_IPC, "IOP: Write32 to IPC_REPLAY_REGISTER(0x08) = 0x%08x ", _rReturnValue);
break;
case IPC_SENSOR_BAR_POWER_REGISTER:
_rReturnValue = g_SensorBarPower;
break;
default:
_dbg_assert_msg_(WII_IPC, 0, "IOP: Read32 from 0x%08x", _Address);
break;
}
}
void HWCALL Write32(const u32 _Value, const u32 _Address)
{
switch(_Address & 0xFFFF)
{
// write only ??
case IPC_COMMAND_REGISTER: // __ios_Ipc2 ... a value from __responses is loaded
{
g_Address = _Value;
LOG(WII_IPC, "IOP: Write32 to IPC_ADDRESS_REGISTER(0x00) = 0x%08x", g_Address);
}
break;
case IPC_CONTROL_REGISTER:
{
LOG(WII_IPC, "IOP: Write32 to IPC_CONTROL_REGISTER(0x04) = 0x%08x (old: 0x%08x)", _Value, g_IPC_Control.Hex);
UIPC_Control TempControl(_Value);
_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.ReplyReady) { g_IPC_Control.ReplyReady = 0; }
if (TempControl.Relaunch) { g_IPC_Control.Relaunch = 0; }
g_IPC_Control.unk5 = TempControl.unk5;
g_IPC_Control.unk6 = TempControl.unk6;
g_IPC_Control.pad = TempControl.pad;
if (TempControl.ExecuteCmd)
{
WII_IPC_HLE_Interface::AckCommand(g_Address);
}
}
break;
case IPC_STATUS_REGISTER: // ACR REGISTER IT IS CALLED IN DEBUG
{
UIPC_Status NewStatus(_Value);
if (NewStatus.INTERRUPT) g_IPC_Status.INTERRUPT = 0; // clear interrupt
LOG(WII_IPC, "IOP: Write32 to IPC_STATUS_REGISTER(0x30) = 0x%08x", _Value);
}
break;
case IPC_CONFIG_REGISTER: // __OSInterruptInit (0x40000000)
{
LOG(WII_IPC, "IOP: Write32 to IPC_CONFIG_REGISTER(0x33) = 0x%08x", _Value);
g_IPC_Config.Hex = _Value;
}
break;
case IPC_SENSOR_BAR_POWER_REGISTER:
g_SensorBarPower = _Value;
break;
default:
{
_dbg_assert_msg_(WII_IPC, 0, "IOP: Write32 to 0x%08x", _Address);
}
break;
}
// update the interrupts
UpdateInterrupts();
}
void UpdateInterrupts()
{
if ((g_IPC_Control.AckReady == 1) ||
(g_IPC_Control.ReplyReady == 1))
{
g_IPC_Status.INTERRUPT = 1;
}
// check if we have to generate an interrupt
if (g_IPC_Config.INT_MASK & g_IPC_Status.INTERRUPT)
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_WII_IPC, true);
}
else
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_WII_IPC, false);
}
}
bool IsReady()
{
return ((g_IPC_Control.ReplyReady == 0) && (g_IPC_Control.AckReady == 0) && (g_IPC_Status.INTERRUPT == 0));
}
void GenerateAck(u32 _AnswerAddress)
{
g_Reply = _AnswerAddress;
g_IPC_Control.AckReady = 1;
UpdateInterrupts();
}
void GenerateReply(u32 _AnswerAddress)
{
g_Reply = _AnswerAddress;
g_IPC_Control.ReplyReady = 1;
UpdateInterrupts();
}
} // end of namespace IPC

View File

@ -0,0 +1,43 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WII_IPC_H_
#define _WII_IPC_H_
namespace WII_IPCInterface
{
// Init
void Init();
// Shutdown
void Shutdown();
// Update
void Update();
bool IsReady();
void GenerateReply(u32 _AnswerAddress);
void GenerateAck(u32 _AnswerAddress);
void HWCALL Read32(u32& _rReturnValue, const u32 _Address);
void HWCALL Write32(const u32 _Value, const u32 _Address);
} // end of namespace AudioInterface
#endif

View File

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

View File

@ -0,0 +1,53 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _HOST_H
#define _HOST_H
// Host - defines an interface for the emulator core to communicate back to the
// OS-specific layer
// The emulator core is abstracted from the OS using 2 interfaces:
// Common and Host.
// Common simply provides OS-neutral implementations of things like threads, mutexes,
// INI file manipulation, memory mapping, etc.
// Host is an abstract interface for communicating things back to the host. The emulator
// core is treated as a library, not as a main program, because it is far easier to
// write GUI interfaces that control things than to squash GUI into some model that wasn't
// designed for it.
// The host can be just a command line app that opens a window, or a full blown debugger
// interface.
void Host_BootingStarted();
void Host_BootingEnded();
void Host_UpdateMainFrame();
void Host_UpdateDisasmDialog();
void Host_UpdateLogDisplay();
void Host_UpdateMemoryView();
void Host_NotifyMapLoaded();
void Host_SetDebugMode(bool enable);
void Host_SetWaitCursor(bool enable);
void Host_CreateDisplay();
void Host_CloseDisplay();
#endif

View File

@ -0,0 +1,366 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <map>
#include <string>
#include "Common.h"
#include "WII_IPC_HLE.h"
#include "WII_IPC_HLE_Device.h"
#include "WII_IPC_HLE_Device_Error.h"
#include "WII_IPC_HLE_Device_DI.h"
#include "WII_IPC_HLE_Device_FileIO.h"
#include "WII_IPC_HLE_Device_stm.h"
#include "WII_IPC_HLE_Device_fs.h"
#include "WII_IPC_HLE_Device_net.h"
#include "WII_IPC_HLE_Device_es.h"
#include "WII_IPC_HLE_Device_usb.h"
#include "WII_IPC_HLE_Device_sdio_slot0.h"
#include "../HW/CPU.h"
#include "../HW/Memmap.h"
#include "../HW/WII_IPC.h"
namespace WII_IPC_HLE_Interface
{
enum ECommandType
{
COMMAND_OPEN_DEVICE = 1,
COMMAND_CLOSE_DEVICE = 2,
COMMAND_READ = 3,
COMMAND_WRITE = 4,
COMMAND_SEEK = 5,
COMMAND_IOCTL = 6,
COMMAND_IOCTLV = 7,
};
typedef std::map<u32, IWII_IPC_HLE_Device*> TDeviceMap;
TDeviceMap g_DeviceMap;
u32 g_LastDeviceID = 0x13370000;
void Init()
{
_dbg_assert_msg_(WII_IPC, g_DeviceMap.empty(), "DeviceMap isnt empty on init");
}
void Shutdown()
{
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
while(itr != g_DeviceMap.end())
{
delete itr->second;
++itr;
}
g_DeviceMap.clear();
}
u32 GetDeviceIDByName(const std::string& _rDeviceName)
{
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
while(itr != g_DeviceMap.end())
{
if (itr->second->GetDeviceName() == _rDeviceName)
return itr->first;
++itr;
}
return 0;
}
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
{
if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
return g_DeviceMap[_ID];
_dbg_assert_msg_(WII_IPC, 0, "IOP tries to access an unknown device 0x%x", _ID);
return NULL;
}
void DeleteDeviceByID(u32 ID)
{
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(ID);
if (pDevice != NULL)
{
delete pDevice;
g_DeviceMap.erase(ID);
}
}
IWII_IPC_HLE_Device* CreateDevice(u32 _DeviceID, const std::string& _rDeviceName)
{
// scan device name and create the right one ^^
IWII_IPC_HLE_Device* pDevice = NULL;
if (_rDeviceName.find("/dev/") != std::string::npos)
{
if (_rDeviceName.c_str() == std::string("/dev/stm/immediate"))
{
pDevice = new CWII_IPC_HLE_Device_stm_immediate(_DeviceID, _rDeviceName);
}
else if (_rDeviceName.c_str() == std::string("/dev/stm/eventhook"))
{
pDevice = new CWII_IPC_HLE_Device_stm_eventhook(_DeviceID, _rDeviceName);
}
else if (_rDeviceName.c_str() == std::string("/dev/di"))
{
pDevice = new CWII_IPC_HLE_Device_di(_DeviceID, _rDeviceName);
}
else if (_rDeviceName.c_str() == std::string("/dev/fs"))
{
pDevice = new CWII_IPC_HLE_Device_fs(_DeviceID, _rDeviceName);
}
else if (_rDeviceName.c_str() == std::string("/dev/net/kd/request"))
{
pDevice = new CWII_IPC_HLE_Device_net_kd_request(_DeviceID, _rDeviceName);
}
else if (_rDeviceName.c_str() == std::string("/dev/net/kd/time"))
{
pDevice = new CWII_IPC_HLE_Device_net_kd_time(_DeviceID, _rDeviceName);
}
else if (_rDeviceName.c_str() == std::string("/dev/es"))
{
pDevice = new CWII_IPC_HLE_Device_es(_DeviceID, _rDeviceName);
}
else if (_rDeviceName.find("/dev/usb/oh1/57e/305") != std::string::npos)
{
pDevice = new CWII_IPC_HLE_Device_usb_oh1_57e_305(_DeviceID, _rDeviceName);
}
else if (_rDeviceName.find("/dev/sdio/slot0") != std::string::npos)
{
pDevice = new CWII_IPC_HLE_Device_sdio_slot0(_DeviceID, _rDeviceName);
}
else
{
PanicAlert("Unknown device: %s", _rDeviceName.c_str());
pDevice = new CWII_IPC_HLE_Device_Error(-1, _rDeviceName);
}
}
else
{
pDevice = new CWII_IPC_HLE_Device_FileIO(_DeviceID, _rDeviceName);
}
return pDevice;
}
std::queue<u32> m_Ack;
std::queue<std::pair<u32,std::string>> m_ReplyQueue;
void ExecuteCommand(u32 _Address);
bool AckCommand(u32 _Address)
{
/* static u32 Count = 0;
LOG(WII_IPC_HLE, "AckAdd: %i", Count);
if (Count == 63)
CCPU::Break();
Count++; */
m_Ack.push(_Address);
return true;
}
void ExecuteCommand(u32 _Address)
{
/* // small dump
switch (Memory::Read_U32(_Address))
{
case COMMAND_OPEN_DEVICE: LOG(WII_IPC_HLE, "COMMAND_OPEN_DEVICE"); break;
case COMMAND_CLOSE_DEVICE: LOG(WII_IPC_HLE, "COMMAND_CLOSE_DEVICE"); break;
case COMMAND_READ: LOG(WII_IPC_HLE, "COMMAND_READ"); break;
case COMMAND_WRITE: LOG(WII_IPC_HLE, "COMMAND_WRITE"); break;
case COMMAND_SEEK: LOG(WII_IPC_HLE, "COMMAND_SEEK"); break;
case COMMAND_IOCTL: LOG(WII_IPC_HLE, "COMMAND_IOCTL"); break;
case COMMAND_IOCTLV: LOG(WII_IPC_HLE, "COMMAND_IOCTLV"); break;
}
for (size_t i=0; i<0x30/4; i++)
{
LOG(WII_IPC_HLE, "Command%02i: 0x%08x", i, Memory::Read_U32(_Address + i*4));
}*/
bool GenerateReply = false;
ECommandType Command = static_cast<ECommandType>(Memory::Read_U32(_Address));
switch (Command)
{
case COMMAND_OPEN_DEVICE:
{
// HLE - Create a new HLE device
std::string DeviceName;
Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
u32 Mode = (DeviceName, Memory::Read_U32(_Address+0x10));
u32 DeviceID = GetDeviceIDByName(DeviceName);
if (DeviceID == 0)
{
// create the new device
// 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.
u32 CurrentDeviceID = g_LastDeviceID;
IWII_IPC_HLE_Device* pDevice = CreateDevice(CurrentDeviceID, DeviceName);
g_DeviceMap[CurrentDeviceID] = pDevice;
g_LastDeviceID++;
GenerateReply = pDevice->Open(_Address);
LOG(WII_IPC_HLE, "IOP: Open (Device=%s, Mode=%i)", pDevice->GetDeviceName().c_str(), Mode);
}
else
{
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
// we have already opened this device
Memory::Write_U32(-6, _Address + 4);
GenerateReply = true;
LOG(WII_IPC_HLE, "IOP: ReOpen (Device=%s, Mode=%i)", pDevice->GetDeviceName().c_str(), Mode);
}
}
break;
case COMMAND_CLOSE_DEVICE:
{
u32 DeviceID = Memory::Read_U32(_Address+8);
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
if (pDevice != NULL)
{
// pDevice->Close(_Address);
LOG(WII_IPC_HLE, "IOP: Close (Device=%s ID=0x%08x)", pDevice->GetDeviceName().c_str(), DeviceID);
DeleteDeviceByID(DeviceID);
GenerateReply = true;
}
}
break;
case COMMAND_READ:
{
u32 DeviceID = Memory::Read_U32(_Address+8);
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
if (pDevice != NULL)
GenerateReply = pDevice->Read(_Address);
}
break;
case COMMAND_WRITE:
{
u32 DeviceID = Memory::Read_U32(_Address+8);
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
if (pDevice != NULL)
GenerateReply = pDevice->Write(_Address);
}
break;
case COMMAND_SEEK:
{
u32 DeviceID = Memory::Read_U32(_Address+8);
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
if (pDevice != NULL)
GenerateReply = pDevice->Seek(_Address);
}
break;
case COMMAND_IOCTL:
{
u32 DeviceID = Memory::Read_U32(_Address+8);
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
if (pDevice != NULL)
GenerateReply = pDevice->IOCtl(_Address);
}
break;
case COMMAND_IOCTLV:
{
u32 DeviceID = Memory::Read_U32(_Address+8);
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
if (pDevice)
GenerateReply = pDevice->IOCtlV(_Address);
}
break;
default:
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown Command %i (0x%08x)", Command, _Address);
CCPU::Break();
break;
}
// seems that the org hw overwrites the command after it has been executed
Memory::Write_U32(8, _Address);
if (GenerateReply)
{
u32 DeviceID = Memory::Read_U32(_Address+8);
IWII_IPC_HLE_Device* pDevice = NULL;
if (g_DeviceMap.find(DeviceID) != g_DeviceMap.end())
pDevice = g_DeviceMap[DeviceID];
if (pDevice != NULL)
m_ReplyQueue.push(std::pair<u32, std::string>(_Address, pDevice->GetDeviceName()));
else
m_ReplyQueue.push(std::pair<u32, std::string>(_Address, "unknown"));
}
}
// Update
void Update()
{
if (WII_IPCInterface::IsReady())
{
// check if an executed must be updated
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
while(itr != g_DeviceMap.end())
{
u32 CommandAddr = itr->second->Update();
if (CommandAddr != 0)
{
m_ReplyQueue.push(std::pair<u32, std::string>(CommandAddr, itr->second->GetDeviceName()));
}
++itr;
}
// check if we have to execute an acknowledged command
if (!m_ReplyQueue.empty())
{
LOG(WII_IPC_HLE, "-- Generate Reply %s (0x%08x)", m_ReplyQueue.front().second.c_str(), m_ReplyQueue.front().first);
WII_IPCInterface::GenerateReply(m_ReplyQueue.front().first);
m_ReplyQueue.pop();
return;
}
if (m_ReplyQueue.empty() && !m_Ack.empty())
{
u32 _Address = m_Ack.front();
m_Ack.pop();
ExecuteCommand(_Address);
LOG(WII_IPC_HLE, "-- Generate Ack (0x%08x)", _Address);
WII_IPCInterface::GenerateAck(_Address);
}
}
}
} // end of namespace IPC

View File

@ -0,0 +1,39 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WII_IPC_HLE_H_
#define _WII_IPC_HLE_H_
namespace WII_IPC_HLE_Interface
{
// Init
void Init();
// Shutdown
void Shutdown();
// Update
void Update();
// Acknowledge command
bool AckCommand(u32 _Address);
} // end of namespace AudioInterface
#endif

View File

@ -0,0 +1,150 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WII_IPC_HLE_DEVICE_H_
#define _WII_IPC_HLE_DEVICE_H_
#include <string>
#include <queue>
#include "../HW/Memmap.h"
#include "../HW/CPU.h"
class IWII_IPC_HLE_Device
{
public:
IWII_IPC_HLE_Device(u32 _DeviceID, const std::string& _rName) :
m_Name(_rName),
m_DeviceID(_DeviceID)
{}
virtual ~IWII_IPC_HLE_Device()
{}
const std::string& GetDeviceName() const { return m_Name; }
u32 GetDeviceID() const { return m_DeviceID; }
virtual bool Open(u32 _CommandAddress) { _dbg_assert_msg_(WII_IPC_HLE, 0, "%s is not able to run Open()", m_Name.c_str()); return true; }
virtual bool Close(u32 _CommandAddress) { _dbg_assert_msg_(WII_IPC_HLE, 0, "%s is not able to run Close()", m_Name.c_str()); return true; }
virtual bool Seek(u32 _CommandAddress) { _dbg_assert_msg_(WII_IPC_HLE, 0, "%s is not able to run Seek()", m_Name.c_str()); return true; }
virtual bool Read(u32 _CommandAddress) { _dbg_assert_msg_(WII_IPC_HLE, 0, "%s is not able to run Read()", m_Name.c_str()); return true; }
virtual bool Write(u32 _CommandAddress) { _dbg_assert_msg_(WII_IPC_HLE, 0, "%s is not able to run Write()", m_Name.c_str()); return true; }
virtual bool IOCtl(u32 _CommandAddress) { _dbg_assert_msg_(WII_IPC_HLE, 0, "%s is not able to run IOCtl()", m_Name.c_str()); return true; }
virtual bool IOCtlV(u32 _CommandAddress) { _dbg_assert_msg_(WII_IPC_HLE, 0, "%s is not able to run IOCtlV()", m_Name.c_str()); return true; }
virtual u32 Update() { return 0; }
protected:
struct SIOCtlVBuffer
{
SIOCtlVBuffer(u32 _Address)
: m_Address(_Address)
{
Parameter = Memory::Read_U32(m_Address +0x0C);
NumberInBuffer = Memory::Read_U32(m_Address +0x10);
NumberPayloadBuffer = Memory::Read_U32(m_Address +0x14);
BufferVector = Memory::Read_U32(m_Address +0x18);
BufferSize = Memory::Read_U32(m_Address +0x1C);
u32 BufferVectorOffset = BufferVector;
for (u32 i=0; i<NumberInBuffer; i++)
{
SBuffer Buffer;
Buffer.m_Address = Memory::Read_U32(BufferVectorOffset); BufferVectorOffset += 4;
Buffer.m_Size = Memory::Read_U32(BufferVectorOffset); BufferVectorOffset += 4;
InBuffer.push_back(Buffer);
}
for (u32 i=0; i<NumberPayloadBuffer; i++)
{
SBuffer Buffer;
Buffer.m_Address = Memory::Read_U32(BufferVectorOffset); BufferVectorOffset += 4;
Buffer.m_Size = Memory::Read_U32(BufferVectorOffset); BufferVectorOffset += 4;
PayloadBuffer.push_back(Buffer);
}
}
const u32 m_Address;
u32 Parameter;
u32 NumberInBuffer;
u32 NumberPayloadBuffer;
u32 BufferVector;
u32 BufferSize;
struct SBuffer { u32 m_Address, m_Size; };
std::vector<SBuffer> InBuffer;
std::vector<SBuffer> PayloadBuffer;
};
void DumpCommands(u32 _CommandAddress, size_t _NumberOfCommands = 8)
{
LOG(WII_IPC_HLE, " CommandDump of %s", GetDeviceName().c_str());
for (u32 i=0; i<_NumberOfCommands; i++)
{
LOG(WII_IPC_HLE, " Command%02i: 0x%08x", i, Memory::Read_U32(_CommandAddress + i*4));
}
}
void DumpAsync( u32 BufferVector, u32 _CommandAddress, u32 NumberInBuffer, u32 NumberOutBuffer )
{
LOG(WII_IPC_HLE, "======= DumpAsync ======");
// write return value
u32 BufferOffset = BufferVector;
Memory::Write_U32(1, _CommandAddress + 0x4);
for (u32 i=0; i<NumberInBuffer; i++)
{
u32 InBuffer = Memory::Read_U32(BufferOffset); BufferOffset += 4;
u32 InBufferSize = Memory::Read_U32(BufferOffset); BufferOffset += 4;
LOG(WII_IPC_HLE, "%s - IOCtlV InBuffer[%i]:", GetDeviceName().c_str(), i);
std::string Temp;
for (u32 j=0; j<InBufferSize; j++)
{
char Buffer[128];
sprintf(Buffer, "%02x ", Memory::Read_U8(InBuffer+j));
Temp.append(Buffer);
}
LOG(WII_IPC_HLE, " Buffer: %s", Temp.c_str());
}
for (u32 i=0; i<NumberOutBuffer; i++)
{
u32 OutBuffer = Memory::Read_U32(BufferOffset); BufferOffset += 4;
u32 OutBufferSize = Memory::Read_U32(BufferOffset); BufferOffset += 4;
Memory::Write_U32(1, _CommandAddress + 0x4);
LOG(WII_IPC_HLE, "%s - IOCtlV OutBuffer[%i]:", GetDeviceName().c_str(), i);
LOG(WII_IPC_HLE, " OutBuffer: 0x%08x (0x%x):", OutBuffer, OutBufferSize);
// DumpCommands(OutBuffer, OutBufferSize);
}
}
private:
std::string m_Name;
u32 m_DeviceID;
};
#endif

View File

@ -0,0 +1,192 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "WII_IPC_HLE_Device_DI.h"
#include "../HW/CPU.h"
#include "../HW/Memmap.h"
#include "../Core.h"
#include "../VolumeHandler.h"
#include "VolumeCreator.h"
#include "Filesystem.h"
// __________________________________________________________________________________________________
//
CWII_IPC_HLE_Device_di::CWII_IPC_HLE_Device_di(u32 _DeviceID, const std::string& _rDeviceName )
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
, m_pVolume(NULL)
, m_pFileSystem(NULL)
{
m_pVolume = DiscIO::CreateVolumeFromFilename(Core::GetStartupParameter().m_strFilename);
if (m_pVolume)
m_pFileSystem = DiscIO::CreateFileSystem(*m_pVolume);
}
// __________________________________________________________________________________________________
//
CWII_IPC_HLE_Device_di::~CWII_IPC_HLE_Device_di()
{
delete m_pFileSystem;
delete m_pVolume;
}
// __________________________________________________________________________________________________
//
bool
CWII_IPC_HLE_Device_di::Open(u32 _CommandAddress)
{
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
return true;
}
// __________________________________________________________________________________________________
//
bool CWII_IPC_HLE_Device_di::IOCtl(u32 _CommandAddress)
{
LOG(WII_IPC_HLE, "*******************************");
LOG(WII_IPC_HLE, "CWII_IPC_HLE_Device_di::IOCtl");
LOG(WII_IPC_HLE, "*******************************");
// DumpCommands(_CommandAddress);
// u32 Cmd = Memory::Read_U32(_CommandAddress + 0xC);
// TODO: Use Cmd for something?
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
LOG(WII_IPC_HLE, "%s - BufferIn(0x%08x, 0x%x) BufferOut(0x%08x, 0x%x)", GetDeviceName().c_str(), BufferIn, BufferInSize, BufferOut, BufferOutSize);
u32 ReturnValue = ExecuteCommand(BufferIn, BufferInSize, BufferOut, BufferOutSize);
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
/* DumpCommands(_CommandAddress);
LOG(WII_IPC_HLE, "InBuffer");
DumpCommands(BufferIn, BufferInSize);
// LOG(WII_IPC_HLE, "OutBuffer");
// DumpCommands(BufferOut, BufferOutSize); */
return true;
}
// __________________________________________________________________________________________________
//
bool CWII_IPC_HLE_Device_di::IOCtlV(u32 _CommandAddress)
{
PanicAlert("CWII_IPC_HLE_Device_di::IOCtlV() unknown");
DumpCommands(_CommandAddress);
return true;
}
// __________________________________________________________________________________________________
//
u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize)
{
u32 Command = Memory::Read_U32(_BufferIn) >> 24;
switch (Command)
{
// DVDLowInquiry
case 0x12:
{
Memory::Memset(_BufferOut, 0, _BufferOutSize);
LOG(WII_IPC_HLE, "%s executes DVDLowInquiry (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
return 0x1;
}
break;
// DVDLowRead
case 0x71:
{
u32 Size = Memory::Read_U32(_BufferIn+0x04);
u64 DVDAddress = (u64)Memory::Read_U32(_BufferIn+0x08) << 2;
const char* pFilename = m_pFileSystem->GetFileName(DVDAddress);
if (pFilename != NULL)
{
LOG(WII_IPC_HLE, " DVDLowRead: %s (0x%x) - (DVDAddr: 0x%x, Size: 0x%x)", pFilename, m_pFileSystem->GetFileSize(pFilename), DVDAddress, Size);
}
else
{
LOG(WII_IPC_HLE, " DVDLowRead: file unkw - (DVDAddr: 0x%x, Size: 0x%x)", GetDeviceName().c_str(), DVDAddress, Size);
}
if (Size > _BufferOutSize)
{
PanicAlert("You try to read more data from the DVD than fit inside the out buffer. Clamp.");
Size = _BufferOutSize;
}
if (VolumeHandler::ReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size) != true)
{
PanicAlert("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
}
return 0x1;
}
break;
// DVDLowGetCoverReg - called by "Legend of Spyro"
case 0x7a:
{
Memory::Memset(_BufferOut, 0, _BufferOutSize);
}
break;
// DVDLowClearCoverInterrupt
case 0x86:
{
Memory::Memset(_BufferOut, 0, _BufferOutSize);
LOG(WII_IPC_HLE, "%s executes DVDLowClearCoverInterrupt (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
}
break;
// DVDLowSeek
case 0xab:
{}
break;
// DVDLowStopMotor
case 0xe3:
{
Memory::Memset(_BufferOut, 0, _BufferOutSize);
LOG(WII_IPC_HLE, "%s executes DVDLowStopMotor (Buffer 0x%08x, 0x%x)", GetDeviceName().c_str(), _BufferOut, _BufferOutSize);
PanicAlert("Weird. Nobody should call DVDLowStopMotor.");
}
break;
default:
LOG(WII_IPC_HLE, "%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);
break;
}
// i dunno but prolly 1 is okay all the time :)
return 1;
}

View File

@ -0,0 +1,48 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WII_IPC_HLE_DEVICE_DI_H_
#define _WII_IPC_HLE_DEVICE_DI_H_
#include "WII_IPC_HLE_Device.h"
namespace DiscIO
{
class IVolume;
class IFileSystem;
}
class CWII_IPC_HLE_Device_di : public IWII_IPC_HLE_Device
{
public:
CWII_IPC_HLE_Device_di(u32 _DeviceID, const std::string& _rDeviceName);
virtual ~CWII_IPC_HLE_Device_di();
bool Open(u32 _CommandAddress);
bool IOCtl(u32 _CommandAddress);
bool IOCtlV(u32 _CommandAddress);
private:
u32 ExecuteCommand(u32 BufferIn, u32 BufferInSize, u32 _BufferOut, u32 BufferOutSize);
DiscIO::IVolume* m_pVolume;
DiscIO::IFileSystem* m_pFileSystem;
};
#endif

View File

@ -0,0 +1,41 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WII_IPC_HLE_DEVICE_ERROR_H_
#define _WII_IPC_HLE_DEVICE_ERROR_H_
#include "WII_IPC_HLE_Device.h"
class CWII_IPC_HLE_Device_Error : public IWII_IPC_HLE_Device
{
public:
CWII_IPC_HLE_Device_Error(u32 _DeviceID, const std::string& _rDeviceName ) :
IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
{}
virtual ~CWII_IPC_HLE_Device_Error()
{}
virtual bool Open(u32 _CommandAddress)
{
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
return true;
}
};
#endif

View File

@ -0,0 +1,171 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "WII_IPC_HLE_Device_FileIO.h"
// smash bros writes to /shared2/sys/SYSCONF
// __________________________________________________________________________________________________
//
CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName )
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
, m_pFileHandle(NULL)
, m_Seek(0)
, m_FileLength(0)
{
m_FileLength = 0;
}
// __________________________________________________________________________________________________
//
CWII_IPC_HLE_Device_FileIO::~CWII_IPC_HLE_Device_FileIO()
{
if (m_pFileHandle != NULL)
{
fclose(m_pFileHandle);
m_pFileHandle = NULL;
}
}
// __________________________________________________________________________________________________
//
bool
CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress)
{
std::string Filename("wii");
Filename += GetDeviceName();
m_pFileHandle = fopen(Filename.c_str(), "r+b");
if (m_pFileHandle != NULL)
{
fseek(m_pFileHandle, 0, SEEK_END);
m_FileLength = ftell(m_pFileHandle);
rewind(m_pFileHandle);
}
else
{
PanicAlert("CWII_IPC_HLE_Device_FileIO: cant open %s", Filename.c_str());
}
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
return true;
}
// __________________________________________________________________________________________________
//
bool
CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
{
LOG(WII_IPC_HLE, "FileIO: Seek (Device=%s)", GetDeviceName().c_str());
DumpCommands(_CommandAddress);
PanicAlert("CWII_IPC_HLE_Device_FileIO: Seek");
u32 ReturnValue = 1;
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
return true;
}
// __________________________________________________________________________________________________
//
bool
CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
{
u32 ReturnValue = 0;
u32 Address = Memory::Read_U32(_CommandAddress +0xC);
u32 Size = Memory::Read_U32(_CommandAddress +0x10);
if (m_pFileHandle != NULL)
{
fread(Memory::GetPointer(Address), Size, 1, m_pFileHandle);
ReturnValue = 1;
LOG(WII_IPC_HLE, "FileIO reads from %s (Addr=0x%08x Size=0x%x)", GetDeviceName().c_str(), Address, Size);
}
else
{
LOG(WII_IPC_HLE, "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);
return true;
}
// __________________________________________________________________________________________________
//
bool
CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
{
LOG(WII_IPC_HLE, "FileIO: Write (Device=%s)", GetDeviceName().c_str());
DumpCommands(_CommandAddress);
PanicAlert("CWII_IPC_HLE_Device_FileIO: Write (Device=%s)", GetDeviceName().c_str());
u32 ReturnValue = 1;
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
return true;
}
// __________________________________________________________________________________________________
//
bool
CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
{
LOG(WII_IPC_HLE, "FileIO: IOCtl (Device=%s)", GetDeviceName().c_str());
DumpCommands(_CommandAddress);
u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
switch(Parameter)
{
case ISFS_IOCTL_GETFILESTATS:
{
LOG(WII_IPC_HLE, "FileIO: ISFS_IOCTL_GETFILESTATS");
LOG(WII_IPC_HLE, "Length: %i Seek: %i", m_FileLength, m_Seek);
Memory::Write_U32(m_FileLength, BufferOut);
Memory::Write_U32(m_Seek, BufferOut+4);
}
break;
default:
{
PanicAlert("CWII_IPC_HLE_Device_FileIO: Parameter %i", Parameter);
}
break;
}
// Return Value
u32 ReturnValue = 0; // no error
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
CCPU::Break();
return true;
}

View File

@ -0,0 +1,70 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WII_IPC_HLE_DEVICE_FILEIO_H_
#define _WII_IPC_HLE_DEVICE_FILEIO_H_
#include "WII_IPC_HLE_Device.h"
class CWII_IPC_HLE_Device_FileIO : public IWII_IPC_HLE_Device
{
public:
CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName);
virtual ~CWII_IPC_HLE_Device_FileIO();
bool Open(u32 _CommandAddress);
bool Seek(u32 _CommandAddress);
bool Read(u32 _CommandAddress);
bool Write(u32 _CommandAddress);
bool IOCtl(u32 _CommandAddress);
private:
enum
{
ISFS_FUNCNULL = 0,
ISFS_FUNCGETSTAT = 1,
ISFS_FUNCREADDIR = 2,
ISFS_FUNCGETATTR = 3,
ISFS_FUNCGETUSAGE = 4,
};
enum
{
ISFS_IOCTL_FORMAT = 1,
ISFS_IOCTL_GETSTATS = 2,
ISFS_IOCTL_CREATEDIR = 3,
ISFS_IOCTL_READDIR = 4,
ISFS_IOCTL_SETATTR = 5,
ISFS_IOCTL_GETATTR = 6,
ISFS_IOCTL_DELETE = 7,
ISFS_IOCTL_RENAME = 8,
ISFS_IOCTL_CREATEFILE = 9,
ISFS_IOCTL_SETFILEVERCTRL = 10,
ISFS_IOCTL_GETFILESTATS = 11,
ISFS_IOCTL_GETUSAGE = 12,
ISFS_IOCTL_SHUTDOWN = 13,
};
FILE* m_pFileHandle;
u32 m_FileLength;
u32 m_Seek;
};
#endif

View File

@ -0,0 +1,149 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WII_IPC_HLE_DEVICE_ES_H_
#define _WII_IPC_HLE_DEVICE_ES_H_
#include "WII_IPC_HLE_Device.h"
#include "../VolumeHandler.h"
// http://wiibrew.org/index.php?title=/dev/es
class CWII_IPC_HLE_Device_es : public IWII_IPC_HLE_Device
{
public:
enum
{
IOCTL_ES_ADDTICKET = 0x01,
IOCTL_ES_ADDTITLESTART = 0x02,
IOCTL_ES_ADDCONTENTSTART = 0x03,
IOCTL_ES_ADDCONTENTDATA = 0x04,
IOCTL_ES_ADDCONTENTFINISH = 0x05,
IOCTL_ES_ADDTITLEFINISH = 0x06,
IOCTL_ES_LAUNCH = 0x08,
IOCTL_ES_OPENCONTENT = 0x09,
IOCTL_ES_READCONTENT = 0x0A,
IOCTL_ES_CLOSECONTENT = 0x0B,
IOCTL_ES_GETTITLECOUNT = 0x0E,
IOCTL_ES_GETTITLES = 0x0F,
IOCTL_ES_GETVIEWCNT = 0x12,
IOCTL_ES_GETVIEWS = 0x13,
IOCTL_ES_DIVERIFY = 0x1C,
IOCTL_ES_GETTITLEDIR = 0x1D,
IOCTL_ES_GETTITLEID = 0x20,
IOCTL_ES_SEEKCONTENT = 0x23,
IOCTL_ES_ADDTMD = 0x2B,
IOCTL_ES_ADDTITLECANCEL = 0x2F,
IOCTL_ES_GETSTOREDCONTENTCNT = 0x32,
IOCTL_ES_GETSTOREDCONTENTS = 0x33,
IOCTL_ES_GETSTOREDTMDSIZE = 0x34,
IOCTL_ES_GETSTOREDTMD = 0x35,
IOCTL_ES_GETSHAREDCONTENTCNT = 0x36,
IOCTL_ES_GETSHAREDCONTENTS = 0x37,
};
CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName) :
IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
{}
virtual ~CWII_IPC_HLE_Device_es()
{}
virtual bool Open(u32 _CommandAddress)
{
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
return true;
}
virtual bool IOCtlV(u32 _CommandAddress)
{
LOG(WII_IPC_HLE, "%s", GetDeviceName().c_str());
SIOCtlVBuffer Buffer(_CommandAddress);
switch(Buffer.Parameter)
{
case IOCTL_ES_GETTITLEDIR:
{
u32 TitleID = VolumeHandler::Read32(0);
if (TitleID == 0)
TitleID = 0xF00DBEEF;
char* pTitleID = (char*)&TitleID;
char* Path = (char*)Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
sprintf(Path, "/title/00010000/%02x%02x%02x%02x/data", (u8)pTitleID[3], (u8)pTitleID[2], (u8)pTitleID[1], (u8)pTitleID[0]);
LOG(WII_IPC_HLE, "CWII_IPC_HLE_Device_es command:"
" IOCTL_ES_GETTITLEDIR: %s", Path);
}
break;
case IOCTL_ES_GETTITLEID:
{
u32 OutBuffer = Memory::Read_U32(Buffer.PayloadBuffer[0].m_Address);
u32 TitleID = VolumeHandler::Read32(0);
if (TitleID == 0)
TitleID = 0xF00DBEEF;
Memory::Write_U32(TitleID, OutBuffer);
LOG(WII_IPC_HLE, "CWII_IPC_HLE_Device_es command:"
" IOCTL_ES_GETTITLEID: 0x%x", TitleID);
}
break;
case 0x16: // Consumption
case 0x1B: // ES_DiGetTicketView
// Mario Galaxy
break;
case IOCTL_ES_GETTITLECOUNT:
{
u32 OutBuffer = Memory::Read_U32(Buffer.PayloadBuffer[0].m_Address);
Memory::Write_U32(0, OutBuffer);
LOG(WII_IPC_HLE, "CWII_IPC_HLE_Device_es command:"
" IOCTL_ES_GETTITLECOUNT: 0x%x", OutBuffer);
}
break;
default:
_dbg_assert_msg_(WII_IPC_HLE, 0, "CWII_IPC_HLE_Device_es: 0x%x", Buffer.Parameter);
DumpCommands(_CommandAddress, 8);
LOG(WII_IPC_HLE, "CWII_IPC_HLE_Device_es command:"
"Parameter: 0x%08x", Buffer.Parameter);
break;
}
// write return value
Memory::Write_U32(0, _CommandAddress + 0x4);
return true;
}
};
#endif

View File

@ -0,0 +1,41 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WII_IPC_HLE_DEVICE_FS_H_
#define _WII_IPC_HLE_DEVICE_FS_H_
#include "WII_IPC_HLE_Device.h"
class CWII_IPC_HLE_Device_fs : public IWII_IPC_HLE_Device
{
public:
CWII_IPC_HLE_Device_fs(u32 _DeviceID, const std::string& _rDeviceName) :
IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
{}
virtual ~CWII_IPC_HLE_Device_fs()
{}
virtual bool Open(u32 _CommandAddress)
{
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
return true;
}
};
#endif

View File

@ -0,0 +1,99 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WII_IPC_HLE_DEVICE_NET_H_
#define _WII_IPC_HLE_DEVICE_NET_H_
#include "WII_IPC_HLE_Device.h"
class CWII_IPC_HLE_Device_net_kd_request : public IWII_IPC_HLE_Device
{
public:
CWII_IPC_HLE_Device_net_kd_request(u32 _DeviceID, const std::string& _rDeviceName) :
IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
{}
virtual ~CWII_IPC_HLE_Device_net_kd_request()
{}
virtual bool Open(u32 _CommandAddress)
{
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
return true;
}
};
class CWII_IPC_HLE_Device_net_kd_time : public IWII_IPC_HLE_Device
{
public:
CWII_IPC_HLE_Device_net_kd_time(u32 _DeviceID, const std::string& _rDeviceName) :
IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
{}
virtual ~CWII_IPC_HLE_Device_net_kd_time()
{}
virtual bool Open(u32 _CommandAddress)
{
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
return true;
}
virtual bool IOCtl(u32 _CommandAddress)
{
u32 Parameter = Memory::Read_U32(_CommandAddress +0x0C);
u32 Buffer1 = Memory::Read_U32(_CommandAddress +0x10);
u32 BufferSize1 = Memory::Read_U32(_CommandAddress +0x14);
u32 Buffer2 = Memory::Read_U32(_CommandAddress +0x18);
u32 BufferSize2 = Memory::Read_U32(_CommandAddress +0x1C);
// write return value
Memory::Write_U32(0, _CommandAddress + 0x4);
LOG(WII_IPC_HLE, "%s - IOCtl:\n"
" Parameter: 0x%x (0x17 could be some kind of Sync RTC) \n"
" Buffer1: 0x%08x\n"
" BufferSize1: 0x%08x\n"
" Buffer2: 0x%08x\n"
" BufferSize2: 0x%08x\n",
GetDeviceName().c_str(), Parameter, Buffer1, BufferSize1, Buffer2, BufferSize2);
return true;
}
};
class CWII_IPC_HLE_Device_net_ip_top : public IWII_IPC_HLE_Device
{
public:
CWII_IPC_HLE_Device_net_ip_top(u32 _DeviceID, const std::string& _rDeviceName) :
IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
{}
virtual ~CWII_IPC_HLE_Device_net_ip_top() {
}
virtual bool Open(u32 _CommandAddress)
{
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
return true;
}
};
#endif

Some files were not shown because too many files have changed in this diff Show More