Ported AdamN's Game Link (Game Boy link) code from 1030e.

Seems to work better with a link timeout of 1.
This commit is contained in:
skidau 2015-03-23 12:17:26 +00:00
parent 0db7dfc323
commit a704653234
6 changed files with 266 additions and 70 deletions

View File

@ -14,6 +14,7 @@
#include "gbSGB.h"
#include "gbSound.h"
#include "../Util.h"
#include "../gba/GBALink.h"
#ifdef __GNUC__
#define _stricmp strcasecmp
@ -796,25 +797,46 @@ void gbWriteMemory(register u16 address, register u8 value)
return;
}
// serial control
case 0x02: {
gbSerialOn = (value & 0x80);
gbMemory[0xff02] = value;
if(gbSerialOn) {
gbSerialTicks = GBSERIAL_CLOCK_TICKS;
#ifdef OLD_GB_LINK
if(linkConnected) {
if(value & 1) {
linkSendByte(0x100|gbMemory[0xFF01]);
Sleep(5);
}
}
#endif
}
// serial control
case 0x02: {
gbSerialOn = (value & 0x80);
#ifndef NO_LINK
if (EmuReseted || (gbMemory[0xff02] & 0x7c) || (value & 0x7c) || (!(value & 0x81))) { //trying to detect whether the game has exited multiplay mode, pokemon blue start w/ 0x7e while pocket racing start w/ 0x7c
LinkFirstTime = true;
}
EmuReseted = false;
gbMemory[0xff02] = value;
if (gbSerialOn) {
gbSerialTicks = GBSERIAL_CLOCK_TICKS;
gbSerialBits = 0;
return;
}
LinkIsWaiting = true;
//Do data exchange, master initiate the transfer
//may cause visual artifact if not processed immediately, is it due to IRQ stuff or invalid data being exchanged?
if ((value & 1) ) { //internal clock
if (gbSerialFunction) {
gbSIO_SC = value;
gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); //gbSerialFunction/gbStartLink/gbPrinter
}
else gbMemory[0xff01] = 0xff;
gbMemory[0xff02] &= 0x7f;
gbSerialOn = 0;
gbMemory[0xff0f] = register_IF |= 8;
}
#ifdef OLD_GB_LINK
if (linkConnected) {
if (value & 1) {
linkSendByte(0x100 | gbMemory[0xFF01]);
Sleep(5);
}
}
#endif
}
gbSerialBits = 0;
return;
#endif
}
case 0x04: {
// DIV register resets on any write
@ -2176,6 +2198,11 @@ void gbGetHardwareType()
void gbReset()
{
#ifndef NO_LINK
EmuReseted = true;
gbLinkReset();
#endif
gbGetHardwareType();
oldRegister_WY = 146;
@ -5204,59 +5231,100 @@ void gbEmulate(int ticksToStop)
gbMemory[0xff41] = register_STAT;
// serial emulation
if(gbSerialOn) {
#ifndef NO_LINK
// serial emulation
gbSerialOn = (gbMemory[0xff02] & 0x80);
static int SIOctr = 0;
SIOctr++;
if (SIOctr % 5)
if (gbSerialOn) { //Transfer Started
#ifdef OLD_GB_LINK
if(linkConnected) {
gbSerialTicks -= clockTicks;
if (linkConnected) {
gbSerialTicks -= clockTicks;
while(gbSerialTicks <= 0) {
// increment number of shifted bits
gbSerialBits++;
linkProc();
if(gbSerialOn && (gbMemory[0xff02] & 1)) {
if(gbSerialBits == 8) {
gbSerialBits = 0;
gbMemory[0xff01] = 0xff;
gbMemory[0xff02] &= 0x7f;
gbSerialOn = 0;
gbMemory[0xff0f] = register_IF |= 8;
gbSerialTicks = 0;
}
}
gbSerialTicks += GBSERIAL_CLOCK_TICKS;
}
} else {
while (gbSerialTicks <= 0) {
// increment number of shifted bits
gbSerialBits++;
linkProc();
if (gbSerialOn && (gbMemory[0xff02] & 1)) {
if (gbSerialBits == 8) {
gbSerialBits = 0;
gbMemory[0xff01] = 0xff;
gbMemory[0xff02] &= 0x7f;
gbSerialOn = 0;
gbMemory[0xff0f] = register_IF |= 8;
gbSerialTicks = 0;
}
}
gbSerialTicks += GBSERIAL_CLOCK_TICKS;
}
}
else {
#endif
if(gbMemory[0xff02] & 1) {
gbSerialTicks -= clockTicks;
if (gbMemory[0xff02] & 1) { //internal clocks (master)
gbSerialTicks -= clockTicks;
// overflow
while(gbSerialTicks <= 0) {
// shift serial byte to right and put a 1 bit in its place
// gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1);
// increment number of shifted bits
gbSerialBits++;
if(gbSerialBits == 8) {
// end of transmission
if(gbSerialFunction) // external device
gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]);
else
gbMemory[0xff01] = 0xff;
gbSerialTicks = 0;
gbMemory[0xff02] &= 0x7f;
gbSerialOn = 0;
gbMemory[0xff0f] = register_IF |= 8;
gbSerialBits = 0;
} else
gbSerialTicks += GBSERIAL_CLOCK_TICKS;
}
}
// overflow
while (gbSerialTicks <= 0) {
// shift serial byte to right and put a 1 bit in its place
// gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1);
// increment number of shifted bits
gbSerialBits++;
if (gbSerialBits >= 8) {
// end of transmission
gbSerialTicks = 0;
gbSerialBits = 0;
}
else
gbSerialTicks += GBSERIAL_CLOCK_TICKS;
}
}
else //external clocks (slave)
{
gbSerialTicks -= clockTicks;
// overflow
while (gbSerialTicks <= 0) {
// shift serial byte to right and put a 1 bit in its place
// gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1);
// increment number of shifted bits
gbSerialBits++;
if (gbSerialBits >= 8) {
// end of transmission
u16 dat = 0;
if (LinkIsWaiting)
if (gbSerialFunction) { // external device
gbSIO_SC = gbMemory[0xff02];
if (!LinkFirstTime)
{
dat = (gbSerialFunction(gbMemory[0xff01]) << 8) | 1;
}
else //external clock not suppose to start a transfer, but there are time where both side using external clock and couldn't communicate properly
{
if (gbMemory)
gbSerialOn = (gbMemory[0xff02] & 0x80);
dat = gbLinkUpdate(gbMemory[0xff01], gbSerialOn);
}
gbMemory[0xff01] = (dat >> 8);
} //else
gbSerialTicks = 0;
if ((dat & 1) && (gbMemory[0xff02] & 0x80)) //(dat & 1)==1 when reply data received
{
gbMemory[0xff02] &= 0x7f;
gbSerialOn = 0;
gbMemory[0xff0f] = register_IF |= 8;
}
gbSerialBits = 0;
}
else
gbSerialTicks += GBSERIAL_CLOCK_TICKS;
}
}
#ifdef OLD_GB_LINK
}
}
#endif
}
#endif
}
soundTicks -= clockTicks;
if ( !gbSpeed )

View File

@ -244,7 +244,8 @@ static const LinkDriver linkDrivers[] =
{ LINK_CABLE_IPC, InitIPC, NULL, StartCableIPC, UpdateCableIPC, CloseIPC },
{ LINK_CABLE_SOCKET, InitSocket, ConnectUpdateSocket, StartCableSocket, UpdateSocket, CloseSocket },
{ LINK_RFU_IPC, InitIPC, NULL, StartRFU, UpdateRFUIPC, CloseIPC },
{ LINK_GAMECUBE_DOLPHIN, JoyBusConnect, NULL, NULL, JoyBusUpdate, JoyBusShutdown }
{ LINK_GAMECUBE_DOLPHIN, JoyBusConnect, NULL, NULL, JoyBusUpdate, JoyBusShutdown },
{ LINK_GAMEBOY, InitIPC, NULL, NULL, NULL, CloseIPC }
};
@ -435,6 +436,11 @@ static const int trtimeend[3][4] = {
static int GetSIOMode(u16, u16);
u8 gbSIO_SC = 0;
bool LinkIsWaiting = false;
bool LinkFirstTime = true;
bool EmuReseted = true;
// The GBA wireless RFU (see adapter3.txt)
static void StartRFU(u16 value)
{
@ -1906,7 +1912,7 @@ bool LinkRFUUpdate()
if (((rfu_cmd == 0x11 || rfu_cmd == 0x1a || rfu_cmd == 0x26) && (GetTickCount() - rfu_lasttime) < 16) ||
((rfu_cmd == 0xa5 || rfu_cmd == 0xb5) && (GetTickCount() - rfu_lasttime) < 16) ||
((rfu_cmd == 0xa7 || rfu_cmd == 0xb7) && (GetTickCount() - rfu_lasttime) < linktimeout))
((rfu_cmd == 0xa7 || rfu_cmd == 0xb7) && (GetTickCount() - rfu_lasttime) < (DWORD)linktimeout))
{
//c_s.Lock();
ok = (linkmem->rfu_listfront[vbaid] != linkmem->rfu_listback[vbaid]);
@ -2691,6 +2697,110 @@ void lclient::Send() {
lanlink.tcpsocket.Send(outbuffer, 4);
return;
}
void gbLinkReset()
{
LinkIsWaiting = false;
LinkFirstTime = true;
linkmem->linkcmd[linkid] = 0;
linkmem->linkdata[linkid] = 0xff;
return;
}
u8 gbStartLink(u8 b) //used on internal clock
{
u8 dat = 0xff; //master (w/ internal clock) will gets 0xff if slave is turned off (or not ready yet also?)
//if(linkid) return 0xff; //b; //Slave shouldn't be sending from here
BOOL sent = false;
//int gbSerialOn = (gbMemory[0xff02] & 0x80); //not needed?
gba_link_enabled = true; //(gbMemory[0xff02]!=0); //not needed?
rfu_enabled = false;
if (!gba_link_enabled) return 0xff;
//Single Computer
if (!lanlink.active)
{
u32 tm = GetTickCount();
do {
WaitForSingleObject(linksync[linkid], 1);
ResetEvent(linksync[linkid]);
} while (linkmem->linkcmd[linkid] && (GetTickCount() - tm)<(u32)linktimeout);
linkmem->linkdata[linkid] = b;
linkmem->linkcmd[linkid] = 1;
SetEvent(linksync[linkid]);
LinkIsWaiting = false;
tm = GetTickCount();
do {
WaitForSingleObject(linksync[1 - linkid], 1);
ResetEvent(linksync[1 - linkid]);
} while (!linkmem->linkcmd[1 - linkid] && (GetTickCount() - tm)<(u32)linktimeout);
if (linkmem->linkcmd[1 - linkid]) {
dat = (u8)linkmem->linkdata[1 - linkid];
linkmem->linkcmd[1 - linkid] = 0;
} //else LinkIsWaiting = true;
SetEvent(linksync[1 - linkid]);
LinkFirstTime = true;
if (dat != 0xff/*||b==0x00||dat==0x00*/)
LinkFirstTime = false;
return dat;
}
return dat;
}
u16 gbLinkUpdate(u8 b, int gbSerialOn) //used on external clock
{
u8 dat = b; //0xff; //slave (w/ external clocks) won't be getting 0xff if master turned off
BOOL recvd = false;
int idx = 0;
gba_link_enabled = true; //(gbMemory[0xff02]!=0);
rfu_enabled = false;
if (gbSerialOn) {
if (gba_link_enabled)
//Single Computer
if (!lanlink.active)
{
u32 tm;// = GetTickCount();
//do {
WaitForSingleObject(linksync[1 - linkid], linktimeout);
ResetEvent(linksync[1 - linkid]);
//} while (!linkmem->linkcmd[1-linkid] && (GetTickCount()-tm)<(u32)linktimeout);
if (linkmem->linkcmd[1 - linkid]) {
dat = (u8)linkmem->linkdata[1 - linkid];
linkmem->linkcmd[1 - linkid] = 0;
recvd = true;
LinkIsWaiting = false;
}
else LinkIsWaiting = true;
SetEvent(linksync[1 - linkid]);
if (!LinkIsWaiting) {
tm = GetTickCount();
do {
WaitForSingleObject(linksync[linkid], 1);
ResetEvent(linksync[linkid]);
} while (linkmem->linkcmd[1 - linkid] && (GetTickCount() - tm)<(u32)linktimeout);
if (!linkmem->linkcmd[linkid]) {
linkmem->linkdata[linkid] = b;
linkmem->linkcmd[linkid] = 1;
}
SetEvent(linksync[linkid]);
}
}
if (dat == 0xff/*||dat==0x00||b==0x00*/) //dat==0xff||dat==0x00
LinkFirstTime = true;
}
return ((dat << 8) | (recvd & (u8)0xff));
}
#else
bool gba_joybus_active = false;
#endif

View File

@ -10,7 +10,8 @@ enum LinkMode
LINK_CABLE_IPC,
LINK_CABLE_SOCKET,
LINK_RFU_IPC,
LINK_GAMECUBE_DOLPHIN
LINK_GAMECUBE_DOLPHIN,
LINK_GAMEBOY
};
/**
@ -193,4 +194,12 @@ typedef struct {
u32 data[255];
} rfu_datarec;
extern u8 gbSIO_SC;
extern bool LinkIsWaiting;
extern bool LinkFirstTime;
extern bool EmuReseted;
extern void gbLinkReset();
extern u8 gbStartLink(u8 b);
extern u16 gbLinkUpdate(u8 b, int gbSerialOn);
#endif /* GBA_GBALINK_H */

View File

@ -73,6 +73,7 @@ BOOL LinkOptions::OnInitDialog(){
AddMode("Cable - Network", LINK_CABLE_SOCKET);
AddMode("GameCube - Dolphin", LINK_GAMECUBE_DOLPHIN);
AddMode("Wireless adapter - Single Computer", LINK_RFU_IPC);
AddMode("Game Link (Game Boy) - Single Computer", LINK_GAMEBOY);
sprintf(timeout, "%d", theApp.linkTimeout);

View File

@ -1025,7 +1025,11 @@ void MainWnd::OnOptionsGameboyPrinter()
if(theApp.winGbPrinterEnabled)
gbSerialFunction = gbPrinterSend;
else
gbSerialFunction = NULL;
#ifndef NO_LINK
gbSerialFunction = gbStartLink;
#else
gbSerialFunction = NULL;
#endif
}
void MainWnd::OnUpdateOptionsGameboyPrinter(CCmdUI* pCmdUI)

View File

@ -1517,7 +1517,11 @@ void VBA::loadSettings()
if(winGbPrinterEnabled)
gbSerialFunction = gbPrinterSend;
else
gbSerialFunction = NULL;
#ifndef NO_LINK
gbSerialFunction = gbStartLink;
#else
gbSerialFunction = NULL;
#endif
pauseWhenInactive = regQueryDwordValue("pauseWhenInactive", 1) ?
true : false;