SNES (Super Nintendo Emulated System)
Going back to the days of ITX computer case mods, I've had the desire to place a computer inside of a stock Super Nintendo case. Instead of the project being a simple case mod, I've wanted to configure the computer in such a way as to maintain a console playing experience, with the additional benefit of having a full-fledged computer under the hood. I've done my research here and there, and everywhere I possibly could, to see how this combination could work. With the Raspberry Pi, I finally found a platform suited to the project's needs.When I came up with the concept in 2004, I had the desire to make an ITX case mod with some of the following features to make the SNES computer "feel" like a console, in no particular order:
- Have both of the case's controller ports functional to all standard SNES peripherals, and have them work as they would on a stock console.
- Design the console to have a fully functioning cartridge port to read Game ROMS, and game saves, and to have the ability to write new game saves back to the cartridges.
- Minimize the cosmetic changes to the case, so that viewing the modified SNES next to a stock console would not throw off an untrained eye. Namely, I did not want to have PC ports cut poorly out the sides.
- Keep the hardware as simple, and solid state as possible. (Use the K.I.S.S method)
- Utilize the Power and Reset buttons as one would intend. Namely, don't require the user to shut down the computer using the display. Have the Power button set up to safely shut down the computer. Also, have the Reset button reset emulation, and re-read the cartridge port.
- Set up an intuitive gaming interface. What is great about classic gaming consoles is you plug in a game, turn it on and play. One should not need to turn on the computer, wait until you boot into Windows, or a command line, and need to use a mouse, or console commands to find an emulator. The machine should turn on, and play a game from Easy Slots, or load a front end. The SNES gaming portion should be front and center.
- Attempt to fully emulate the speed, and functionality of the original hardware. Where possible, allow for the improving of the original experience by offering image filtering, the use of save states, and other modern emulation goodies. With the base system being the base gaming experience of the original hardware.
What inspired me to take up the project after so many years with a Raspberry Pi was a Hack-A-Day post I saw where Florian wrote a C-Based Daemon to interface SNES controllers directly to the Pi's GPIO bus. A spark went off in my head. When I wanted to make an SNES computer prior, all the the ITX boards I wanted to use were PC based, and the best I could use for GPIO was a standard PC parallel port, and it leaves much to be desired...A couple of other advantages of using a Raspberry Pi is it's absolutely small size, and minimal power requirements. Not only could I fit it inside of an SNES case, I could theoretically also power it using a stock SNES wall wart. Not to mention it also had analog video and stereo audio. Both are AV sources I could simply wire to a stock SNES AV port.. Also, with the Pi's HDMI port, the thought was with not too much modification, I could add it to the back, fulfilling my desire to expand the features of the console.View the video below for a brief demonstration of the completed project.http://www.youtube.com/watch?v=qEJuDdjkVSc&feature=youtu.beMy code may be found through my repository on GitHub.For a detailed explanation on EVERYTHING, read the following pages:With a spare SNES cartridge connector I had been kicking around, and a taken apart console I previously had been gutting parts from, I had all the motivation I needed!I started by lining up a perfboard with the spacings of an original SNES motherboard, and cut holes in the perfboard to line it with the case. I then lined up the spare SNES cartridge connector I had to fit the cartridge opening on the top half of the case, as it's the one part of the motherboard that absolutely had to line up.I had also desoldered the back IO plane from the original SNES motherboard as the power connector is a part of the plastic. The standard AV port was also desoldered, and I was pleasantly surprised to find that it's component pins were spaced the standard 0.1" apart. So I was able to drop it right into the perfboard. As you could see from the image below, lining these few components was a relative breeze..To interface the cartridge port to the Raspberry Pi, I had originally decided to use Microchip MCP23S17 SPI-based IO expanders, but I had also bought it's sister chip, the MCP23017, which is I2C based. Both versions allow the expansion of 16 I/O pins. Expanding the Pi's GPIO pins are a necessity given the number of I/O pins a standard SNES cart uses; 16 Address, and 8 Bank control pins, along with 8 Data out pins, and at least 4 control pins. Totaling 36 pins needed to read most carts. I would need to use at least three of these expansion chips.The SPI version of the expander has a 10MHz communications clock, while the I2C version only has a maximum 1.7MHz clock. Also, the Raspberry Pi has had notoriously slow I2C drivers, with a configured clock rate of only 100KHz. Despite the obvious speed advantages of the SPI bus, I found that code examples were lacking. I also realized that I would need to run additional bus wire, on what would be a very populated hand soldered board. On top of that, I had a P82B96PN I2C level translator ready to use, and with SPI I'd have to level translate additional lines, because the Pi uses 3.3v logic, and all the SNES components uses 5v logic.As you could see above, hand soldering all these pins was not for the faint of heart, and this was only the beginning! It was also around this time that I had the idea of utilizing the unused Ext Port door for USB, thus the USB socket above. The pin headers on the top center were to connect a daughter-board where the Pi was going to rest..I decided to not go with a PCB daughter-board in the end as I didn't want a permanent extension of the main PCB as I may need to solder under it. Nor did I have the female headers to make it removable. Plus, it added unnecessary complexity. In the end I went with an Adafruit's GPIO ribbon cable to connect the Raspberry Pi to the perfboard. I desoldered, and cut up a 40-pin female IDE header from an old motherboard, and dremeled it down to the 26-pins the ribbon cable needed, and made a spot for it.It was around this I started focusing on powering the system, and a way to safely power down the system with the stock power switch.Next up, DC-DC converters, Arduinos, and MOSFETs. Oh my!I wanted to use the stock SNES AC-Adapter to power the system, so I had to find out what it's output was rated for.According to the label, the AC Adapter is rated to provide 850mA at 10v. Nintendo is known for quality, so I trust the labeling, and accept that the wall wart could provide what it is labeled.As the Model B Raspberry Pi runs on 5v, and could use upwards of 700mA, I needed a way to step down the voltage to 5v. Going by Ohms law, and assuming the impractical notion you could convert the voltage with 100% efficiency, you'd have 1700mA power at 5v, but we live in the real world. Actual Super Nintendos use a 7805 linear voltage regulator with heatsink to step down the voltage. While this may have been logical in 1991, and still economical today, there are MUCH better ways of doing things.I ended up using a Murata DC-DC converter that is rated to provide up to 2 Amps of power @ 5v. According to the data sheet, it is 95% efficient when stepping down 10v. Rough math tells me 95% of the 1700mA I provided earlier gives me 1615mA to work with. To be safe, I placed a 1.5A pico fuse in the circuit, in fact, this is the same value a stock SNES uses. This is cutting it close as the Raspberry Pi typically only begins acts stable when provided with an 1A PSU, but I felt the rest of the peripherals shouldn't drain too much current. Connecting any high-current USB devices, like a hard drive would likely trip the fuse, but I'll be mindful not to do that. ;)
If you examine the picture above, you could see I kind of threw in the kitchen sink. A few things to note; on the bottom right corner is a Reset button I stole from an SNES motherboard. It lines up to the case's Reset button, and will be used later. The unpopulated socket directly above it is reserved for a SuperCIC Lock. The SuperCIC emulates an original SNES CIC chip which is used to check for pirated games. Nintendo got smart later in the consoles life, and started using the "key" in some carts to scan for unauthorized copying equipment by scanning for a lock. I reserved this space as I imagine I may need it for SA-1 games.
As the Pi has no real power management, I needed a way to safely power off the system using the power switch, thus using the switch to physically disconnect the power was a huge no-no. I purchased a P-Channel MOSFET that was way over-kill, and has a nominal Gate-Source voltage of -10v, despite being marketed as being TTL controlled, but using 5v logic is fine. Basically pulling the gate low passes voltage.The MOSFET is configured to switch power to the entire system with the exception of the power management circuit I have to monitor the switch state, and safely shut down the Pi.The way I configured the Arduino to do this isn't elegant, but it works given the limitations. Basically, when the file system, and really the Linux kernel shuts down, the Serial UART TX Pin that is typically a HIGH 3.3v goes low. When the user switches off the power switch, the Arduino logs in to the Serial terminal as a user, and issues a poweroff command. The Arduino then monitors the stat of the Pi's TX pins. Once the pin goes low, and stays low, I turn off the MOSFET. The detection of this occurring is represented with the green LED in the video below..http://youtu.be/1i8tjzlAPTIIf the Pi doesn't safely power down after about 40 seconds, the Arduino attempts to log in as a user again, and send the poweroff command one last time. If the Pi doesn't power down about 30 seconds after this, the Arduino kills the power anyway, as life goes on, right?Connected to the Power Management circuit of things powered all the time is an 74HCT125N chip used to step up the Clock and Latch lines used by both SNES controllers from 3.3v to the 5v logic that they need. It also steps up the Pi's TX pin that connects to the Arduino. While the Arduino will accept 3.3v as logic high, the chip is there, so why not use it? Also connected is a 74LVC245AN chip needed to step down the SNES controllers 5v Data pin logic to something that won't damage the Pi. It also steps down the ATMega's TX pin used to log into the computer.I kept both chips powered at all times as there is a feature to hold their I/O lines in high impedance, and I didn't want to have the chips powered off in an environment of a mixed power state. I could probably rethink this, but it works for now.Next up, setting up the I2C bus, and SNESDev-Pi controller driver..To set up I2C on the Raspberry Pi, I used a guide from SK Pang Electronics. After following the guide, and running "i2cdetect," all I2C chips on the bus should register it's address.The "-y" flag stops the command from issuing warnings about probing the bus. The number, in this case 1, indicates which bus to scan. The Raspberry Pi actually has two separate I2C buses. On the original Model B Raspberry Pis, the bus broken out to GPIO header pins 3, and 5 are set as bus '0.' On revision 2 of the Raspberry Pi, these pins now map to bus '1.' Keep that in mind when adapting code between the newer and older model Pis.Another thing to note is the address of the chips. MCP23017 chips register on the bus starting at address 0x20. There are three hardware address pins on the chips that when pulled high or low change the addressing of that particular chip. Giving a possibility of 8 of these chips on a single bus. I meant for these chips to read sequentially, but I derped when visualizing the binary addresses, thus there is no chip at address 0x21. It's no big deal, though.For the next step, I installed the SNESDev-RPi controller drivers....and this caused problems. Not only did the controllers not register, but now my I2C bus no longer worked. Over the course of the next few days I debugged the hardware as I thought I may have caused a short, or even fried some GPIO pins.It wasn't until I delved into the source of SNESDev-RPi where I found the problem. The pinout on the blog was no longer used by the code:
// pin out used in SNESDev article on blog// pads.clock = RPI_GPIO_P1_18;// pads.strobe = RPI_GPIO_P1_16;// pads.data1 = RPI_GPIO_P1_22;// pads.data2 = RPI_GPIO_P1_15;
// pin out used pi gamecon GPIO driverpads.clock = RPI_GPIO_P1_19;pads.strobe = RPI_GPIO_P1_23;pads.data1 = RPI_GPIO_P1_07;pads.data2 = RPI_GPIO_P1_05;
The pinout was apparently changed to follow the convention of another coder's "gamecon" GPIO driver. I had already wired my circuit around the old pinout, and on top of that "RPI_GPIO_P1_05" is also the I2C SDL pin. This explained why I2C stopped working, as well.I commented out the gamecon pin mappings, and un-commented the original pin maps. I recompiled, and tested. Not only did the I2C bus report my expanders, my controllers now worked! It was actually a good thing that I went through the source, as I found that a little referenced feature of the driver was the ability to use a GPIO pin as a button. As it was configured by the driver, pressing the button sends an "ESC" key press to the terminal, and holding the button then releasing causing the system to shut down. (It would have been nice to know about this while working on the power management!)I would come to revisit this code later on the wiring up of the Reset Button..Next up, cartridge reading!After I set up the hardware and the Linux environment, I was ready to read and rip cartridges! So where to start? I remember reading about a SNES cartridge reader that would later be known as the Retrode on Hack-a-Day. So I went to read one of the original blog posts to see what resources the original engineer used.The only resource mentioned was an old blog, titled "SNES Kart." It is hosted on emularonia.com and was written by DiskDude. While the resource helped tremendously, a lot of it is a collection of observations DiskDude made way back in 1996. Since then, let's just say there are less uncertainties; a lot of time has passed, and the SNES hardware has been thoroughly reverse engineered by now. A break down of this information was a pain in the ass to find though.Try Googling "Reading SNES Cartridges." Most of the results link you to already available commercial solutions, or a forum post where the answer is using a commercial solution.The other 99% of the results are for reading ABOUT the SNES, and nothing technical. Searching for "Ripping" or "Dumping" largely links to ROM sites. The obvious issue is that every commercial SNES title has already been ripped, and not too many people are interested in re-ripping them. I wanted to though, damn it!
To spare time, I will break down my findings. Use the notes below as a supplement to other ROM reading documents on the internet. I'm going to document things I feel will save others time.SNES Cartridges have:
- 4 Control Pins, and an IRQ Pin. To read a cart, hold the control pins RD, and CS low. WR Should be held high. Also, RESET should be held high, despite the "SNES Kart" document indicating the opposite. The IRQ pin can send a signal from the cart to the console when the CPU should be halted. I'm not sure if it will ever be necessary for cartridge reading, but I broke it out just in case.
- 4 CIC Security Check Pins. In SNES consoles there is a chip known as the "CIC" chip. This chip acts as an anti-counterfeiting "lock," and will hold the console in reset until it is unlocked by the corresponding "key" in a legitimate cartridge. Cartridges typically don't care if the CIC lock is missing from the device communicating to it, and some people would disable this chip to thwart the anti-piracy.Nintendo got smart to this, and games with SA-1 chips actually won't work if the CIC chip doesn't communicate with it. The CIC chips have been reverse engineered, and the SuperCIC was designed to emulate the original chip, and will work as a drop-in replacement. I haven't attempted to emulate the CIC yet, but expect to have to in order to read games such as Super Mario RPG.
- 16 OPTIONAL "Bus B" (Expansion Chip) Pins. If you've ever looked at the bottom of a Super FX game, or any other cartridge with an expansion chip, you'll notice an additional 16 pins on both sides of the center PCB. As far as I can conclude, these are useful for speedy (CPU<>Expansion Chip) communications. While I wouldn't be surprised if a handful of carts use these pins for transferring ROM data at faster rates, I don't expect you'll ever NEED them to dump a cart. Besides, every expansion chipped game I've visually inspected seem to only utilize the SNES clock pin. (Likely for sync)
- 16 Address pins, and an 8-pin Data Bus. When you move to an address, the 8-bit piece of data held at that address could be read from the data bus. If you understand bits, bytes, and binary, this shouldn't be too hard to follow so far.As 8 bits are in a byte, in actuality there is exactly 1 byte at every address read. Counting by the number of addresses (2^16), you'll find that you could read up to 65536 bytes, which converts to 64 Kilobytes. SNES games often contain a lot more data, so how do you read more than 64Kilobytes? By switching banks!
- 8 Bank pins, giving a maximum of 256 banks that could be accessed. There are two ways of bank switching you must be aware of. One method for LoROM, and another for HiROM games. HiROM reading is simply the matter of incrementing the address for the full 16-bit length. Then you increment the bank, and read the next 64 Kilobytes. LoROM games only use half of each bank, leaving only 32 Kilobytes per bank.
Reading LoROMs:The way I understood LoROM addressing was to read the first 32 Kilobytes, switch banks,and then read the next lower 32KB, starting again at address 0. Many different resources seemed to allude that having pin A15 high was optional, but this is not the case.In actuality, you NEED to hold A15 high with LoROMs, so you are in essence reading the UPPER 32KB. Many docs say that the lower 32KB is mirrored with the top 32KB on LoROM games. NOPE. Super Mario World worked reading the lower half, Super Metroid did not, though.All SNES games hold a standardized header at the same address. The SNES Kart document has this address at two separate offsets, depending on LoROM or HiROM. In practice, these two addresses are the same.The header for LoROM games is said to be held at offset DEC: 32704. This is
- 0111111111000000 in binary.
The header for HiROM games is said to be held at offset DEC: 65472. This is
- 1111111111000000 in binary.
Notice the only difference is at bit 15.My code ORs a '1' to bit 15 regardless of the specified address in LoROM mode. So moving to address 32704 in LoROM is actually 65472 when accounting for that fact that A15 will be high.ROM Type Detection, and Checksums:So the question you may be asking is how would you know if a game is LoROM or HiROM? Good question! It's in the header! As I mentioned, since the header is at the same location on both types of ROMs, the nibble containing the ROM type is, as well.The ROM Type is at address DEC:65493, contained in the lower nibble.
- 0x0 is for LoROM, and
- 0x1 is for HiROM.
If the cartridge connector is dirty, the Data Pins will not be accurate, or in the case where these is no cart, will be held high by the MCP23017's internal pull-up resistors.A good way to test if a cartridge is connected, and is working properly is to check it's checksum bytes.In SNES carts, at addresses DEC:65500-65501 are two bytes that make up a 16-bit ROM Checksum. Lower byte at 65500, and upper byte at 65501.There is also an 16-bit Inverse Checksum at addresses DEC:65002-65003, respectively.XOR'ing the ROM Checksum to the Inverse Checksum should produce 0xffff. If it does not, I assume that the cartridge data is invalid. As this is stored in the header, I could check for this rather quickly.
As an example, Super Mario Kart has a ROM Checksum of 0xeb44, and the Inverse Checksum is 0x14bb. XOR-ing them together equals 0xfff.
The ROM checksum is also the last 16-bits of the calculated checksum from reading the contents of the cartridge. For example, Super Mario Kart is a 512 Kilobyte HiROM game. Since it's HiROM, you read in 64-Kilobyte "pages.* (512/64 = 8 pages.) When reading a ROM, add each byte of 64-Kilobyte pages together, then add the results of each page together.
For Super Mario Kart, the calculated checksum is 0x286eb44.The 16-bit ROM Checksum in the header is 0xeb44. Notice the header checksum is indeed the last 16-bits of the fully calculated checksum..
To know how many pages will need to be read, in addition to the ROM type, you'd need to know the ROM size. This too is stored in the header, at offset DEC:65494. Unfortunately, it's size is listed as exponents of 2. The size in Megabits can be 2, 4, 8, 16, or 32 Megabits, but games could be of different sizes.
Super Metroid is a 24 Megabit game, but going by the header, is listed as a 32 Megabit game. In this case I read the full 32-Megabits, and calculated the checksum. It matches the checksum in the header, but it's possible the file size is 8 Megabits longer than it has to be. It works for now, though, and I doubt emulators will care there is data passed the declared ROM length.
What address to begin reading at:For both HiROM, and LoROM games I used to start at offset 0. That is Address 0, and Bank 0. I started noticing checksum errors, so I attempted to clarify. It helps to actually have some very specific knowledge to Google search with! I used the search term for "SNES rom" with hexadecimal addresses I had been using and finally found comments in source code.I found a SNES ROM reading driver for the M.E.S.S (Multi-Emulator Super System) Project, and used the memory maps it uses.In short:For LoRom Games:
- Read up to 96 possible pages starting at bank 0x00.
For HiROM Games:
- Read the first 64 pages beginning at bank 0xc0.
- IF the ROM is larger than 32-Megabits (VERY rare!,) read the final 32 pages starting at bank 0x40.
and that's about it. I haven't attempted to read or write save game data yet, but that too is just a matter of software.For additional reading, use these resources:http://wiki.superfamicom.org/snes/show/Memory+Mappinghttp://en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_maphttp://www.programmersheaven.com/download/13299/4/ZipView.aspxNext, the Reset Switch, along with Bash and Python scripting..I chose Python to read carts as I've used it a lot in the past, and felt it would be useful for quick rewrites. The trade-off is that it's an interpreted language, and is not nearly as efficient or quick as C++.When it came down to reading carts, I found that the ripping speed was not as fast as I'd hope due to the Pi's configured I2C speed. The time needed was dependent on the size of the game, with most titles being between 4 to 16 Megabits. I was finding that an 8-Megabit title would take almost 18 minutes to rip. As you'd only need to rip a cartridge once, a long wait may be tolerable for a one time deal, but the waits became extreme for larger titles.For example, ripping Donkey Kong Country, a full 32-Megabit title, took a little over 70 minutes. I set out to find a way to increase the speed of the Pi's I2C bus, and finally found a solution on the official Raspberry Pi forums. Using Modprobe, I was able to force the I2C bus to operate at a faster rate, and well, the results were rather astounding. DKC now ripped in about 34 minutes. That is more than twice as fast!To prevent re-ripping of already read carts, I check the Game Title which is in the header represented by 21-characters. When reading a cart, I have been using the full 21 characters as it is for the file name. This is less than ideal as many game titles have trailing spaces, and some will have a not so detailed Game Title. For instance, A Legend of Zelda: A Link to the Past has the header name of "THE LEGEND OF ZELDA ". This is not so bad considering there was only one Zelda title for the SNES, and the title is close to 21 characters, but for automating game ripping I may include a way to manually enter a Game Title in the future.The python script I wrote, "cart_reader.py" sets up the SNES Cart reader by turning on a MOSFET I connected to the cartridge port for hot-swapping games. It then initializes the address, bank, and control lines by changing their states from input to output. I normally keep all the pins as inputs so they are in high impedance; this also helps the cartridge port go into isolation for hot-swapping.The next step is to scan the checksums, and if valid pulls the game title. The game title text is then written to /tmp/insertedCart. If the game title matches an existing file name by the same Game Title, it quits, else it rips. If no valid game is found, the text "NULL" is written to insertedCart.The BASH script "cartCheckAndEmulate.sh" runs cart_reader.py and when done uses the text of insertedCart to pass as an argument to the emulator to be called next. If no cartridge was detected, it launches EmulatioStation, a front end for Raspberry Pi Game ROMs, namely the ones previously ripped.As previously mentioned, I modified SNESDev-RPi for my Reset Button. When the Reset is pressed, it sended the ESC key to the console, then the F4 key. ESC is to quit out of the emulator, if it is running, and to then quit out of EmulationStation, assuming that is running. It then launches cartCheckAndEmulate.sh. As all of this is being invoked by a daemon, I ran into issues.Originally, I was using RetroArch with PocketSNES libs for SNES emulation, but found that the emulation speed was quite lacking with sound enabled. More importantly for use with the Reset Button, it uses raw keyboard drivers. When it is not launched from a console connected to the keyboard, it refuses to accept keyboard input. As both the controllers, and the Reset button sends virtual keyboard presses to the emulator, this became a serious problem.For decent emulation speed with sound enabled, I went with an ancient build of SNES9X. It's emulation accuracy is not nearly as accurate as recent emulators, but was deisgned for much older harder, and as such works for my purposes. More importantly, when evoked by a daemon, still allows key presses. I modified my cartCheckAndEmulate script, and when called without an argument, uses RetroArch. If called with any argument, uses SNES9x. With a quick re-code, the Reset Button now works as I intended.My modified SNESDev-Rpi fork may be found here.To further aid in emulation speed,recently I decided to finally mess with the Raspberry Pi's "Core" overclock, ...again. You see, back in September, 2012, the Raspberry Pi Foundation announced an officially sanctioned way to "safely" overclock the Pi using rasp-config. I utilized this overclock for when Eben and Liz Upton of the Raspberry Pi Foundation came to visit our hackerspace. I had a music controlled Raspberry Pi stop light display ready to go, and when the event was ready to start, my image corrupted. I found out later from Eben that Core overclocks have been known to corrupt SD cards.The new official Core overclock doubles the Core speed from 250MHz to 500MHz. The thinking of the community is that maintaining the same ratio of the 250MHz clock, in this case twice the clock, helps.It helped not only in emulation, but in cart ripping. Look at my Results with Donkey Kong Country below!
It took 4213.22911692seconds to read cart - Default Core & I2C speedIt took 2036.41756105seconds to read cart - Default Core; Increased I2C BaudIt took 1172.85034895seconds to read cart - 500MHz Core; Increased I2C Baud
Next up, some final thoughts..With the Raspberry Pi, I was able to achieve all of the goals I originally set out for, except Full speed emulation. Sadly, I doubt that the Rapberry Pi will ever be capable of running something along the lines of BSNES; cycle-accurate, exact emulation. In my testing, Retroarch using the PocketSNES core emulates the SNES on the Raspberry Pi the best, but only is playable when sound is disabled. A viable alternative to PocketSNES is an older build of SNES9x, v1.39 that was ported by palerider of the Raspberrypi.org forums.The older SNES9x build was deigned for much slower computers than we're accustomed to today, and thus makes use of different hacks and shortcuts to produce emulation, and the result isn't nearly as accurate as newer emulators. The plus though is the SNES9x build allows for sound emulation at acceptable game play speeds. Unfortunately, the sound emulation follows quality of the rest of the emulation; it is not implemented well. Nor is expansion chipped games, such as Star Fox supported.I managed to fit all the components neatly inside the case, and gave up for now on trying to extend HDMI to the back panel. I also went with a WiFi dongle over Ethernet to keep things tidy.USB was routed through pins 2&3 of the stock SNES controller ports as they aren't mapped to any standard 1st or 3rd party controller. I made custom SNES Controller Port <> USB dongles to connect keyboards from outside the case.Early in the build process I had considered making the SNES Audio Processing Unit a permanent fixture of the project, but decided against it to save time, and to not cram the space inside of the console. I did make an enclosure for one of the removable Audio Processing Units, and placed the design on Thingiverse, so I imagine I could revisit this idea later.In fact, Eben and Liz Upton of the Raspberry Pi Foundation stopped by our hackerspace while on their hackerspace tour, and I picked Eben's brain a little on how I could mix the APU's audio back into the Pi. Eben seemed to think that the I2S bus could be a viable interface to mix audio into the Pi as a sort of Line-Input. I even got Eben to sign the APU! He felt guilty though, as he commented that it was like signing a piece of computer history. After a bit of nudging, he agreed though. :DAll being said though, I believe the Raspberry Pi is a capable closed platform, and with enough community support, full speed SNES emulation should be possible. I'd like to even make kits out of this project, and kickstart it. Maybe along the lines of the RetroDuo, only Raspberry Pi enabled. Maybe with GPIO connected external processors to aid the Pi.