165 changes: 92 additions & 73 deletions Source/Core/Core/Src/HW/SI_DeviceGBA.cpp
Expand Up @@ -17,6 +17,7 @@

#include "SI_Device.h"
#include "SI_DeviceGBA.h"
#include "GBAPipe.h"

//////////////////////////////////////////////////////////////////////////
// --- GameBoy Advance ---
Expand All @@ -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)
Expand All @@ -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<EBufferCommands>(_pBuffer[iPosition ^ 3]);
iPosition++;

// handle it
switch(command)

// read the command
EBufferCommands command = static_cast<EBufferCommands>(_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:
{
//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]);

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:
{
// 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

*(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;
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;
}
Expand All @@ -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;
}
Expand All @@ -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);
}
27 changes: 19 additions & 8 deletions Source/Core/Core/Src/HW/SI_DeviceGBA.h
Expand Up @@ -35,19 +35,27 @@ class CSIDevice_GBA : public ISIDevice
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?)
Expand All @@ -66,6 +74,9 @@ class CSIDevice_GBA : public ISIDevice
// Constructor
CSIDevice_GBA(int _iDeviceNumber);

// Destructor
~CSIDevice_GBA();

// Run the SI Buffer
virtual int RunBuffer(u8* _pBuffer, int _iLength);

Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/Src/SConscript
Expand Up @@ -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",
Expand Down