Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Link cable support #28

Closed
pepijndevos opened this issue Feb 3, 2015 · 13 comments
Closed

Link cable support #28

pepijndevos opened this issue Feb 3, 2015 · 13 comments

Comments

@pepijndevos
Copy link

It would be so cool to fight my friends on Pokemon Red/Blue without buying a ton of ancient hardware.

Would it be possible to support this at all? Either between two emulator instances, or a cable to an actual Game Boy. There might be some issues with timing on multitasking OSes.

As I understand it, it's basically an SPI cable where the the master is the first to start clocking. At least on the Raspi, it could maybe actually talk to a Game Boy using SPI over the GPIO pins.

I have no idea how it's done in software on the real Game Boy. I suspect you can write a byte to some register? Or do you manually clock the lines? Does the clock signal have any effect on the internal clock?

If it is at all possible, and given some hand-holding, I would like to look into this.

@pepijndevos
Copy link
Author

I did a little digging.

I found a programming manual, which tells me there is a serial data register at FF01 and a control register at FF02. There is also an interrupt when a transfer is completed, but I need to dig into that more..

It seems u8 IORegistersMemoryRule::PerformRead(u16 address) and void IORegistersMemoryRule::PerformWrite(u16 address, u8 value) are responsible for these registers.

I wonder if it'd work to simply write to spidev on the Raspi. The hardware seems to be master-only.

@drhelius
Copy link
Owner

drhelius commented Feb 3, 2015

I think it's possible. Look here for documentation: http://problemkaputt.de/pandocs.htm#serialdatatransferlinkcable

Someone tried it before but I'm afraid he didn't finish it: https://github.com/abarisain/Gearboy
There you can see the registers implemented in u8 IORegistersMemoryRule::PerformRead(u16 address) and void IORegistersMemoryRule::PerformWrite(u16 address, u8 value)

https://github.com/abarisain/Gearboy/blob/master/src/IORegistersMemoryRule.cpp#L229

@drhelius
Copy link
Owner

drhelius commented Feb 3, 2015

The serial interrupt is somewhat emulated. I can't remember but I'm sure some games won't work if some parts of the serial thing is not implemented, even when running in single player.

Look: https://github.com/drhelius/Gearboy/blob/master/src/Processor.cpp#L406

@pepijndevos
Copy link
Author

Ok, so it seems the fork has a framework in place, but no implementation of actually sending anything. It handles the registers, and then finally calls some function pointer that goes nowhere. It also seems to contain some unrelated/outdated changes.

So the big question is this function pointer. Maybe an initial hack based on a FIFO could work. I wonder what @abarisain had in mind.

It seems that currently the interrupt code just emulates a disconnected Game Boy?
I think this code is not needed with the fork, but there is a lot I don't understand, that is maybe related to timing?

@drhelius
Copy link
Owner

drhelius commented Feb 3, 2015

I don't have a clue, the fork is outdated but I just spotted some bugs regarding his usage of the SetBit method.

If I remember it, the current serial code is emulating an interrupt request when a transfer is finished (the 8 bits are sent).

@abarisain
Copy link

I kind of dropped the idea, and didn't delete the repo for some reason. After studying how the link cable works in depth, it would never have worked with what I had in mind (I wanted to add Bluetooth multiplayer) since the link cable requires precise clock timings. I don't remember the specifics, but I think that the gameboys talked and listened according to a clock timing, which would be impossible to implement with a Bluetooth transport.

Anyway, maybe you can get this working with the RaspPi, but as you said, I think that the multitasked nature of the OS will get in your way.
Retroarch implemented what I had in mind next : run two emulators locally, make them talk to eachother directly (no timing issue !). I think the iOS solution would have been to run 2 instances of the emulator on the same device, and then stream the video/controls from one phone to the other.

@pepijndevos
Copy link
Author

Right, it's more like SPI than Serial, by which I mean it's synchronous. The master sends a clock signal, and the slave responds. You send and receive bits at the same time, although in practice you usually send and ignore the result or receive while sending zeroes.

When you are the slave, the master Game Boy might send a byte, wait a few ms and then send a zero(drive the clock line) to receive the response. If your BT stack doesn't have a response yet, you're toast.

On the other hand, if you are the master, you drive the clock, So in that case you can write as slowly as you want, provided you do if fast enough for the game to work. You might even pause the emulator.

So yes, bluetooth would be troublesome. Synchronous IPC (shared memory, FIFO file, etc.) or an actual SPI might work, I think?

@pepijndevos
Copy link
Author

@abarisain meanwhile, do you have any info about Retroarch? Not as cool as the real deal, but still fun to play with. I installed it, but don't see any option for opening and connecting two windows.

@pepijndevos
Copy link
Author

So no luck with Retroarch. There seems to be one Windows-only dual emulator. Meh.

It seems like this should be doable. I ordered a link cable to hook up to the Raspi. If any of you can remember more about the latency/timing requirements, that would be super helpful.

@abarisain
Copy link

I'm sorry, I don't.

And yeah, the Windows only emulator is the one with working link. The source is hard to read though :)

@pepijndevos
Copy link
Author

So I'm giving up on this idea. While it would be possible to do it via shared memory, talking to a Game Boy using a Raspberry Pi is not possible.

And Arduino works great, and I have this working, but the Linux kernel adds to much latency to do it on the Raspi. There is hardware for SPI, but slave mode is not well supported and uses a different pin. So switching between master and slave like the Game Boy does is not possible.

@drhelius
Copy link
Owner

Not even pausing the emulation?

@pepijndevos
Copy link
Author

I havn't touched the emulator so far. I just wrote a program to talk to the gameboy without doing anything else. It just misses a bit now and then. So when the gameboy sends 0x01 you start to read 0x02, 0x08, 0x20, etc...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants