From 95cf4cd86b98b9290215c5832583b830a3d88b99 Mon Sep 17 00:00:00 2001 From: Shawn Hoffman Date: Fri, 6 Mar 2009 23:35:49 +0000 Subject: [PATCH] experimental GBA stuff for XK :) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2578 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/HW/GBAPipe.cpp | 177 +++++++++++++++++++++++ Source/Core/Core/Src/HW/GBAPipe.h | 51 +++++++ Source/Core/Core/Src/HW/SI.cpp | 6 +- Source/Core/Core/Src/HW/SI_DeviceGBA.cpp | 161 ++++++++++++--------- Source/Core/Core/Src/HW/SI_DeviceGBA.h | 27 +++- Source/Core/Core/Src/SConscript | 1 + 6 files changed, 341 insertions(+), 82 deletions(-) create mode 100644 Source/Core/Core/Src/HW/GBAPipe.cpp create mode 100644 Source/Core/Core/Src/HW/GBAPipe.h diff --git a/Source/Core/Core/Src/HW/GBAPipe.cpp b/Source/Core/Core/Src/HW/GBAPipe.cpp new file mode 100644 index 0000000000..fad046b8e9 --- /dev/null +++ b/Source/Core/Core/Src/HW/GBAPipe.cpp @@ -0,0 +1,177 @@ +// 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 +#endif + +#include "Common.h" +#include "../Core.h" + +#include "GBAPipe.h" +#include "../PowerPC/PowerPC.h" +#include "CommandProcessor.h" + + +#include "../Host.h" + +#ifdef _WIN32 + +namespace GBAPipe +{ + + HANDLE m_hPipe; + bool m_bIsServer; + bool m_bEnabled; + u32 m_BlockStart; + +#define PIPENAME "\\\\.\\pipe\\gbapipe" + + + void SetBlockStart(u32 addr) + { + m_BlockStart = addr; + } + + void StartServer() + { + if (m_bEnabled) + return; + + //TODO: error checking + m_hPipe = CreateNamedPipe( + PIPENAME, + PIPE_ACCESS_DUPLEX, // client and server can both r+w + PIPE_WAIT |/* PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,*/ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, + 1, //maxinst + 0x1000, //outbufsize + 0x1000, //inbufsize + INFINITE, //timeout + 0); + + if (m_hPipe == INVALID_HANDLE_VALUE) + { + INFO_LOG(SERIALINTERFACE, "Failed to create pipe."); + } + else + { + INFO_LOG(SERIALINTERFACE, "Pipe %s created.", PIPENAME); + } + + m_bIsServer = true; + m_bEnabled = true; + } + + void ConnectAsClient() + { + if (m_bEnabled) + return; + + //TODO: error checking + m_hPipe = CreateFile( + PIPENAME, + GENERIC_READ|GENERIC_WRITE, + 0, //share + NULL, + OPEN_EXISTING, + 0, + NULL); + + if (m_hPipe == INVALID_HANDLE_VALUE) + { + INFO_LOG(SERIALINTERFACE, "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); + m_bEnabled = false; + } + } + + void Read(u8& data) + { + if (!m_bEnabled) + return; + + u32 read; + memset(&data, 0x00, sizeof(data)); // pad with zeros for now + HRESULT result = ReadFile(m_hPipe, &data, sizeof(data), (LPDWORD)&read, FALSE); + if (FAILED(result)/* || read != sizeof(data)*/) + { + INFO_LOG(SERIALINTERFACE, "Failed to read pipe %s", PIPENAME); + Stop(); + } + else + { + INFO_LOG(SERIALINTERFACE, "read %x bytes: 0x%02x", read, data); + } + } + + void Write(u8 data) + { + if (!m_bEnabled) + return; + + u32 written; + HRESULT result = WriteFile(m_hPipe, &data, sizeof(data), (LPDWORD)&written,FALSE); + if (FAILED(result)) + { + INFO_LOG(SERIALINTERFACE, "Failed to write to pipe %s", PIPENAME); + Stop(); + } + else + { + INFO_LOG(SERIALINTERFACE, "Wrote %x bytes: 0x%02x", written, data); + } + } + + bool IsEnabled() + { + return m_bEnabled; + } + + bool IsServer() + { + return m_bIsServer; + } + + +} +#else + +namespace GBAPipe +{ + void StartServer() { } + void ConnectAsClient() { } + void Stop() { } + void Read(u32& data){} + void Write(u32 data){} + bool IsEnabled() { return false; } + bool IsServer() { return false; } +} +// #error Provide a GBAPipe implementation or dummy it out, please + +#endif diff --git a/Source/Core/Core/Src/HW/GBAPipe.h b/Source/Core/Core/Src/HW/GBAPipe.h new file mode 100644 index 0000000000..18d040683f --- /dev/null +++ b/Source/Core/Core/Src/HW/GBAPipe.h @@ -0,0 +1,51 @@ +// 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 GBAPipe +{ + // start the server + void StartServer(); + + // connect as client + void ConnectAsClient(); + + // stop + void Stop(); + + // Transfer funcs + void Read(u8& data); + void Write(u8 data); + + // IsEnabled + bool IsEnabled(); + + // IsServer + bool IsServer(); + + void SetBlockStart(u32 addr); +} + +#endif diff --git a/Source/Core/Core/Src/HW/SI.cpp b/Source/Core/Core/Src/HW/SI.cpp index 9d30334b6c..f36e3c84dc 100644 --- a/Source/Core/Core/Src/HW/SI.cpp +++ b/Source/Core/Core/Src/HW/SI.cpp @@ -533,9 +533,9 @@ void ChangeDeviceCallback(u64 userdata, int cyclesLate) { u8 channel = (u8)(userdata >> 32); // doubt this matters... -// g_Channel[channel].m_Out.Hex = 0; -// g_Channel[channel].m_InHi.Hex = 0; -// g_Channel[channel].m_InLo.Hex = 0; + g_Channel[channel].m_Out.Hex = 0; + g_Channel[channel].m_InHi.Hex = 0; + g_Channel[channel].m_InLo.Hex = 0; // raise the NO RESPONSE error switch (channel) diff --git a/Source/Core/Core/Src/HW/SI_DeviceGBA.cpp b/Source/Core/Core/Src/HW/SI_DeviceGBA.cpp index ce916b4169..4f91c175da 100644 --- a/Source/Core/Core/Src/HW/SI_DeviceGBA.cpp +++ b/Source/Core/Core/Src/HW/SI_DeviceGBA.cpp @@ -17,6 +17,7 @@ #include "SI_Device.h" #include "SI_DeviceGBA.h" +#include "GBAPipe.h" ////////////////////////////////////////////////////////////////////////// // --- GameBoy Advance --- @@ -25,6 +26,13 @@ CSIDevice_GBA::CSIDevice_GBA(int _iDeviceNumber) : ISIDevice(_iDeviceNumber) { + GBAPipe::StartServer(); + js.U16 = 0; +} + +CSIDevice_GBA::~CSIDevice_GBA() +{ + GBAPipe::Stop(); } int CSIDevice_GBA::RunBuffer(u8* _pBuffer, int _iLength) @@ -33,80 +41,91 @@ int CSIDevice_GBA::RunBuffer(u8* _pBuffer, int _iLength) ISIDevice::RunBuffer(_pBuffer, _iLength); int iPosition = 0; - while(iPosition < _iLength) - { - // read the command - EBufferCommands command = static_cast(_pBuffer[iPosition ^ 3]); - iPosition++; - // handle it - switch(command) + // read the command + EBufferCommands command = static_cast(_pBuffer[3]); + iPosition++; + + // handle it + switch(command) + { + // NOTE: All "Send/Recieve" mentioned here is from dolphin's perspective, + // NOT the GBA's + // This means the first "Send"s are seen as CMDs to the GBA, and are therefor IMPORTANT :p + // Also this means that we can randomly fill recieve bits and try for a fake gba... + // (try playing with the fake joystat) + // It seems like JOYSTAT is polled all the time, it's value may or may not matter + case CMD_RESET: { - // NOTE: All "Send/Recieve" mentioned here is from dolphin's perspective, - // NOT the GBA's - // This means "Send"s are seen as CMDs to the GBA, and are therefor IMPORTANT :p - // Also this means that we can randomly fill recieve bits and try for a fake gba... - // for example, the ORd bits in RESET and STATUS are just some values to play with - case CMD_RESET: - { - //Device Reset - //Send 0xFF - //Recieve 0x00 - //Recieve 0x04 - //Recieve from lower 8bits of SIOSTAT register + //Send 0xFF + GBAPipe::Write(CMD_RESET); + //Recieve 0x00 + //Recieve 0x04 + //Recieve from lower 8bits of JOYSTAT register + for (;iPosition < _iLength; ++iPosition) + GBAPipe::Read(_pBuffer[iPosition]); - *(u32*)&_pBuffer[0] = SI_GBA;//|2; - iPosition = _iLength; // break the while loop - INFO_LOG(SERIALINTERFACE, "GBA %i CMD_RESET", this->m_iDeviceNumber); - } - break; - case CMD_STATUS: - { - //Type/Status Data Request - //Send 0x00 - //Recieve 0x00 - //Recieve 0x04 - //Recieve from lower 8bits of SIOSTAT register - - *(u32*)&_pBuffer[0] = SI_GBA;//|8; - iPosition = _iLength; // break the while loop - INFO_LOG(SERIALINTERFACE, "GBA %i CMD_STATUS", this->m_iDeviceNumber); - } - break; - case CMD_WRITE: - { - //GBA Data Write (to GBA) - //Send 0x15 - //Send to Lower 8bits of JOY_RECV_L - //Send to Upper 8bits of JOY_RECV_L - //Send to Lower 8bits of JOY_RECV_H - //Send to Upper 8bits of JOY_RECV_H - //Receive from lower 8bits of SIOSTAT register - - INFO_LOG(SERIALINTERFACE, "GBA %i CMD_WRITE", this->m_iDeviceNumber); - } - break; - case CMD_READ: - { - //GBA Data Read (from GBA) - //Send 0x14 - //Receive from Lower 8bits of JOY_TRANS_L - //Receive from Upper 8bits of JOY_TRANS_L - //Receive from Lower 8bits of JOY_TRANS_H - //Receive from Upper 8bits of JOY_TRANS_H - //Receive from lower 8bits of SIOSTAT register - - INFO_LOG(SERIALINTERFACE, "GBA CMD_READ"); - } - break; - default: - { - WARN_LOG(SERIALINTERFACE, "GBA %i unknown command (0x%x)", this->m_iDeviceNumber, command); - iPosition = _iLength; - } - break; + js.U16 = 0; // FAKE + js.stat_send = 1; // FAKE + *(u32*)&_pBuffer[0] |= SI_GBA | js.U16; // hax for now + WARN_LOG(SERIALINTERFACE, "GBA %i CMD_RESET", this->m_iDeviceNumber); } + break; + case CMD_STATUS: + { + //Send 0x00 + GBAPipe::Write(CMD_STATUS); + //Recieve 0x00 + //Recieve 0x04 + //Recieve from lower 8bits of JOYSTAT register + for (;iPosition < _iLength; ++iPosition) + GBAPipe::Read(_pBuffer[iPosition]); + + js.U16 = 0; // FAKE + js.stat_rec = 1; // FAKE + *(u32*)&_pBuffer[0] |= SI_GBA | js.U16; // hax for now + WARN_LOG(SERIALINTERFACE, "GBA %i CMD_STATUS", this->m_iDeviceNumber); + } + break; + // Probably read and write belong in getdata and sendcommand + case CMD_WRITE: + { + //Send 0x15 + GBAPipe::Write(CMD_WRITE); + //Send to Lower 8bits of JOY_RECV_L + //Send to Upper 8bits of JOY_RECV_L + //Send to Lower 8bits of JOY_RECV_H + //Send to Upper 8bits of JOY_RECV_H + for (;iPosition < _iLength-1; ++iPosition) + GBAPipe::Write(_pBuffer[iPosition]); + //Receive from lower 8bits of JOYSTAT register + GBAPipe::Read(_pBuffer[++iPosition]); + + WARN_LOG(SERIALINTERFACE, "GBA %i CMD_WRITE", this->m_iDeviceNumber); + } + break; + case CMD_READ: + { + //Send 0x14 + GBAPipe::Write(CMD_READ); + //Receive from Lower 8bits of JOY_TRANS_L + //Receive from Upper 8bits of JOY_TRANS_L + //Receive from Lower 8bits of JOY_TRANS_H + //Receive from Upper 8bits of JOY_TRANS_H + //Receive from lower 8bits of JOYSTAT register + for (;iPosition < _iLength; ++iPosition) + GBAPipe::Read(_pBuffer[iPosition]); + + WARN_LOG(SERIALINTERFACE, "GBA %i CMD_READ", this->m_iDeviceNumber);; + } + break; + default: + { + WARN_LOG(SERIALINTERFACE, "GBA %i CMD_UNKNOWN (0x%x)", this->m_iDeviceNumber, command); + } + break; } + INFO_LOG(SERIALINTERFACE, "GBA buffer %08x",*(u32*)&_pBuffer[0]); return iPosition; } @@ -117,7 +136,7 @@ int CSIDevice_GBA::RunBuffer(u8* _pBuffer, int _iLength) bool CSIDevice_GBA::GetData(u32& _Hi, u32& _Low) { - INFO_LOG(SERIALINTERFACE, "GBA %i GetData Hi: 0x%x Low: 0x%x", this->m_iDeviceNumber, _Hi, _Low); + INFO_LOG(SERIALINTERFACE, "GBA %i GetData Hi: 0x%08x Low: 0x%08x", this->m_iDeviceNumber, _Hi, _Low); return true; } @@ -128,5 +147,5 @@ CSIDevice_GBA::GetData(u32& _Hi, u32& _Low) void CSIDevice_GBA::SendCommand(u32 _Cmd) { - INFO_LOG(SERIALINTERFACE, "GBA %i SendCommand: (0x%x)", this->m_iDeviceNumber, _Cmd); + INFO_LOG(SERIALINTERFACE, "GBA %i SendCommand: (0x%08x)", this->m_iDeviceNumber, _Cmd); } diff --git a/Source/Core/Core/Src/HW/SI_DeviceGBA.h b/Source/Core/Core/Src/HW/SI_DeviceGBA.h index c1416f0e39..6a5a781185 100644 --- a/Source/Core/Core/Src/HW/SI_DeviceGBA.h +++ b/Source/Core/Core/Src/HW/SI_DeviceGBA.h @@ -35,19 +35,27 @@ private: CMD_READ = 0x14 }; - struct FAKE_JOYSTAT + union FAKE_JOYSTAT { - unsigned unused : 1; - unsigned stat_rec : 1; - unsigned unused2 : 1; - unsigned stat_send : 1; - unsigned genpurpose : 2; - unsigned unused3 :10; + u16 U16; + struct{ + unsigned :1; + unsigned stat_rec :1; // GBA-side reception status flag + unsigned :1; + unsigned stat_send :1; // GBA-side transmission status flag + unsigned gp0 :1; // General-purpose flag 0 + unsigned gp1 :1; // General-purpose flag 1 + unsigned :2; + + unsigned :8; + }; }; + FAKE_JOYSTAT js; ////////////////////////////////////////////////////////////////////////// //0x4000158 - JOYSTAT - Receive Status Register (R/W) (ON THE GBA) ////////////////////////////////////////////////////////////////////////// - // NOTE: I am guessing that JOYSTAT == SIOSTAT, may be wrong + // NOTE: there is a typo in GBATEK! + // in the JOY BUS command descriptions, SIOSTAT==JOYSTAT //Bit Expl. //0 Not used //1 Receive Status Flag (0=Remote GBA is/was receiving) (Read Only?) @@ -66,6 +74,9 @@ public: // Constructor CSIDevice_GBA(int _iDeviceNumber); + // Destructor + ~CSIDevice_GBA(); + // Run the SI Buffer virtual int RunBuffer(u8* _pBuffer, int _iLength); diff --git a/Source/Core/Core/Src/SConscript b/Source/Core/Core/Src/SConscript index 2db8157954..881dda4369 100644 --- a/Source/Core/Core/Src/SConscript +++ b/Source/Core/Core/Src/SConscript @@ -51,6 +51,7 @@ files = ["Console.cpp", "HW/SI.cpp", "HW/SI_Device.cpp", "HW/SI_DeviceGBA.cpp", + "HW/GBAPipe.cpp", # TEMPORARY "HW/SI_DeviceGCController.cpp", "HW/StreamADPCM.cpp", "HW/SystemTimers.cpp",