gacube emeleter

On the origins of nocoffei

This article requires some introduction. Said introduction is, at the same time, an intro to the name of my website and my internet handle.

On June 9, 2016, an unfortunate teenager by the name of petermary17 attempted to hack his 3DS. It did not go well for him.

<petermary17> Hey I have a question, my 3ds is stuck on a black screen, what should I do?
<CheatFreak> Did you just doengrade to 2.1 and are getting a blackscreen?
<petermary17> no, installing a9lh bricked me

The short version is that at the time, peter was attempting to install an exploit that required some console-specific data. But instead of using his consoles own data, he found another consoles data online, and installed the exploit using that. His 3DS was instantly permanently bricked.1

<petermary17> I didnt got my OTP as I already had an OTP.bin
<CheatFreak> Welp, you're permabricked
<petermary17> why?
<CheatFreak> Because OTP files are 3DS specific
<petermary17> 😮
<CheatFreak> You can't use one generated by another 3DS for yours
<CheatFreak> doesn't work like that
<petermary17> is there a way to recover
<petermary17> like recovey mode
<Paradiddle> Did the guide tell you to download an OTP.bin file?
<petermary17> i downloaded one from the internet
<Paradiddle> oh
<Paradiddle> wow
<petermary17> but they told to generate mine
<petermary17> but I grabbed my online
<CheatFreak> Welp you're done, get another 3DS

Peter didn’t take this very well. He went to the piracy forum GBATemp, which hosts many people attempting to hack their consoles, and started writing.

The original petermary17 text. It says:

Like now i have 11.0 new 3ds white color and i updated to 11.0 can someone develop exploit quick for me or community send in pm if possible please. 

I have hmbrew acess with freakyforms delixe and own 6 copies so can run homebrew plase can some devs get to work or release what they doen .
I mean eh we got arm11 with homebrew and we cant even run lima3ds wtf. so we could downgrade becase arm11-arm9-downgrade someone can create 11.0 downgkader?????
@d0k3 @Aurora Wright @mid-kid @Plailect @Apache Thunder

At first glance this is gibberish, and largely it is. Grammar, punctuation and spelling were absent. He asked for “some devs” to make an “11.0 downgrader”, referring to some anti-downgrade checks introduced in 3DS firmware 11.0 which allowed userland homebrew to run, but prevented custom firmware from being installed.

petermary17 was eventually banned from GBATemp for spamming, after running a massive thread for a few days. But he returned.

The first post made by the account petermary17beck. It says:

EH, ME just wantejsd downgsrefer fasst and ds pligsn limma33ds fet me no coeefei!!!!!
cmon isnt thate hard me no rpogeram devd sonblihgateion they are basteards biilies and
stupid .
me just awnt dowsnrade me 3ds plilect briked when adwongrading 9.9 plilect fautt nao me
want idngereder cmon not harr me want oklhigatieon
@astronaultlevel @Aurora Wright @Plailect @Apache Thunder @shutterbug2000
@d0k3 @mid-kid @Rinnegatamante @cearp @TheCruel @Steveice10
NO COEEFEI i want downtgaodaere no bully me want nao quik fest no mods be bckea no
woof tipsic
egein me atag becuuse devs obligateons me not naow ewhy beeeneed but me ajsust want
wdingereder comnn quick decs bved i want NAO NAO.
EGEIme have 6 copies frakafoerms me have hb reprotam patch no coe€ei it prosible devs
have gdevs dnont relesae devs stuoud
no cofefei me beck

The petermary17beck account racked up 10 pages of forum posts before he was banned.

Peters voice became increasingly unhinged. Forum posts lasted multiple pages. Moderators banned him as fast as he could create new accounts.

Memes started being made.

An image of a man wearing a fedora. The lenses of his glasses are the default GBATemp icon (which peter used on all of his accounts). Overlaid are various pieces of text containing peter text, and one image of a crossed-out coffee cup (which is the same image this website uses as its header.)

Logging on to GBATemp in the morning, one could either wake up and find a new peter alt or shitposting about his past activities in the Edge of the Forum.

A modified version of the poster for the 2016 film "The Secret Life of Pets", with the text "The Secret Life of Peters". The dog has the text "Tink Dis Wat Obligate Dev?" above its head.

I find it difficult to explain the true depth of this story. It lasted for quite some time. Peters participation in the community ran deep, with some really inspired shitposting coming out of his keyboard.

A meme saying:
"When you're hitting it from behind and she turn around and moan, PLILECT FUCKHI BRIKEND ME IS NOT STEBKE IS RISKY HE JTOE SSABIAD SME"
A hand slams toward a button with the text "GACUBE DONGRODER" on it.

Peter had become a legend amidst this small, piracy-ridden, entitled community of homebrewers. And that is the origin of the handle and website “nocoffei”— a strange, incoherent statement often inserted into the middle of his rants that ended up becoming his catchphrase.2

A nearly complete archive of the petermary17 story can be found on My gratitude to Seriel, Techinicabor, and CheatFreak47 for preserving this little corner of history.3


One day, peter posted this.

The first post from the account "peterpeter". It says:

eh sl gacube an 3ds 3ds is mor peweful and mor powe more spepdd so wyh not gacube
emilitir gor 3ds?
Cen sumeone criite gecube or nds roms emilitir(nitivr) for lima3ds?
I wanr and I dont want h䠊eshcarf
Do it now is devs obo呅੪hation
@Plailect @Aurora Wright @Apache Thunder @astronautlevel @shutterbug2000
@bunnei @Rinnegatamante @Steveice10 @TheCruel @Wolfvak @d0k3
Aldo plilect gault me brickrd 3d sme wat dwnfrsdet 11.0 or liam3ds suppot 11.0 or am9
kenel eplit nao its devs oligstion and nuine gmme aniting

This thread lasted for a record-breaking 23 pages before peterpeter was banned. The gacube emeleter instantly became a meme, seeping into the pop culture of the forum just like the rest of Peters story.

Most of the things Peter asked for eventually came true. The 3DS can now be hacked on all firmwares, including, should one desire, the ability to downgrade from an 11.0+ firmware.

The gacube emeleter, however, was never finished. And it was, and still is, the “devs obofihation4

We, the devs, are obligated. Let’s make it happen.

A modified Nintendo GameCube logo that instead says "Nintendo GaCube".

This will never work

The 3DS is rather a potato of a computer. If we think back to 2011, phones weren’t very fast… And in typical Nintendo fashion, the 3DS’ hardware was already obsolete before it was released. Let’s take a look at the GameCubes hardware versus the 3DS’ hardware:

Nintendo GameCube Specs
PowerPC “Gekko” @ 486MHz
Custom ATI “Flipper” GPU @ 162MHz
Nintendo 3DS Specs
2x ARM11 MPCore @ 268MHz
DMP PICA200 GPU @ 268MHz

The GameCube was a very powerful piece of hardware in its time. Normally, comparing numbers at face value is pointless, but for our purposes it works quite well— if one CPU has a clock speed (number of steps taken per second) lower than the other one, how could it hope to handle the enormous amounts of overhead that emulation requires? It can’t. The 3DS is not capable of emulating the GameCube at full speed.

Maybe exclusively targeting the New 3DS will help?

Nintendo GameCube Specs
PowerPC “Gekko” @ 486MHz
Custom ATI “Flipper” GPU @ 162MHz
New Nintendo 3DS Specs
4x ARM11 MPCore @ 804MHz
DMP PICA200 GPU @ 268MHz

Still not good enough. At least the CPU runs faster.

As a final nail in the coffin, the 3DS’ successor, the vastly more powerful Nintendo Switch, cannot emulate the GameCube at full speed either.


The property of Turing Completeness states that, given unbounded time and memory, any computer can compute any task. This scientific law of computing means that the 3DS must be capable of emulating the GameCube, assuming unbounded time and memory.

Peter never specified that the emeleter should run well. It should just run at all. So fulfilling his requirements is, indeed, possible.

Comic from
Props to Randall Munroe for coming rather close to predicting the contents of this blog post.

None of these words are in the Bible

How do you approach this?

First we’ll need an emulator. In this case, the choice is quite simple— Dolphin Emulator. It’s the only program on the market for this job, and for good reason.

Dolphin is an extremely complex piece of software. It’s over 20 years old, has millions of lines of code, and is even used by the Visual Studio developers as a torture test for their compilers.

It has an incredible laundry list of features. Just off the top of my head, it includes:

  • Just-In-Time recompilers
    • For x86_64 and aarch64
  • Four graphics backends
    • OpenGL, Vulkan, Direct3D 11, Direct3D 12
  • A completely self-contained Bluetooth stack
  • Network play architecture
  • A TAS playback system
  • Ubershaders
  • Etc. etc. etc.

Dolphin is highly advanced, highly mature, and just works. It plays your games, and plays them well. It’s everything software should be.

So how do you approach running it on the 3DS?

Well, when you strip Dolphin down to its core dependencies, it turns out it doesn’t require that much. Although Dolphin has a massive amount of tight optimizations and clever tricks for running fast on contemporary CPUs and GPUs, it offers the ability to strip them all away at build time and enable a “generic build” which will run on anything you want. So our requirements are:

  • A supported operating system running on the 3DS
  • The ability to read a GameCube ISO
  • Graphics drivers
    • Dolphin always expects an OpenGL context to be present, even when using the software renderer.
  • A display to output to

These requirements aren’t that steep. We can make this work on the 3DS.

Operating System and Disk Reader

There’s a port of Linux for the 3DS. It’s very incomplete, but is usable. You get working displays, gamepad buttons, and a touchscreen display. All CPU cores can be brought up and run at full speed. Missing are wi-fi drivers, GPU drivers, power management, and a lot of other things necessary to make it work well.

Recent patches enable mounting the SD card. So we’re in business with the ability to read the ISO.

However, only the kernel is present, and the userland provided by the linux-3ds project is buildroot. buildroot is, briefly, completely insufficient to run Dolphin. We will need a more practical userland environment for our purposes.

At this point I stalled for a few months. Configuring buildroot to build Dolphin would have been punishingly difficult. Then, during a conversation with Mueller Minki, I found out that he had a key insight.

The original 2011 Raspberry Pi, and its miniature twin, the Raspberry Pi Zero, has a single-core ARM1176JZFS CPU. This is an armv6l processor, that additionally has support for the Jazelle execution state (which is a topic for another article). Its officially supported operating system, Raspbian, still gets releases to this day, thanks to the first-class support from the Raspberry Pi Foundation.

The ARM11 MPCore CPUs found in the 3DS are armv6k CPUs, a superset of armv6l. So, as it turns out, Raspbian is nearly completely drop-in compatible with the 3DS! Unfortunately, a custom initramfs is needed, as some things like systemd are broken. Minki wrote one that he asserts will be open sourced Soon™, after it’s cleaned up. You can message him for the current version.

Graphics drivers and display output

linux-3ds has no GPU drivers. Even if it did, it would not be possible to use them. The PICA200 GPU on the 3DS is fully compliant with the OpenGL ES 1.1 standard, and is almost compatible with OpenGL ES 2.0— however, it has a unique fixed-function configurable fragment pipeline that breaks the standard, which requires shaders.

The fragment pipeline of the PICA200 can be thought of much like the GameCubes Texture Environment Unit, but worse. It could never hope to emulate the GameCube. So we’ll need to do all the GPU emulation on the CPU.

Dolphin has a software renderer built in that doesn’t utilize a graphics card. However, it does require a valid OpenGL context for presentation of the frames it completes. It would be possible to write a new presentation scheme that avoids this, but it might have been difficult— Neither I nor the Dolphin devs could figure out exactly how their current framebuffer driver depends on OpenGL5. They also said that their software renderer was truly terrible performance-wise, and that I would likely be better off using a software OpenGL backend like llvmpipe.

Another problem is that the 3DS’ top screen is only 400×320 pixels. The GameCube outputs at 640×480, which means that the 3DS’ screen simply won’t be able to present the entire frame.

So how do we start up llvmpipe? Well, we’ll need an X session to connect to, since an OpenGL context depends on a display server in the Linux graphics stack. But without a graphics card, it’ll be difficult to start an X session. This Catch-22 was subverted with a second observation from Minki.

The TigerVNC server shipped with Raspbian includes llvmpipe. So if one were to create a TigerVNC session, they would get a full-sized display of any desired resolution, and they would get an X session with llvmpipe built in. Two birds with one stone.

We have successfully fulfilled all of Dolphins requirements to run. We have an OS with Linux, a device from which we can read an ISO. a display output and some graphics drivers. We can now start building Dolphin.

Developing for linux-3ds

Attempting to develop this Dolphin port on the console would be ill-advised.

There is a tiny, terrible touchscreen keyboard that uses the 3DS’ imprecise resistive touchscreen. There are no drivers for the wi-fi card, so SSH is not possible. Though it is technically possible to gain networking by ripping out the consoles IR blaster and soldering to it for use as a UART (the hardware can be configured to work as a UART port instead of an IR port), there is a better (and much less destructive) way.

qemu-user-static is a program that allows userspace programs written for another ISA to execute on a host ISA using qemu. The kernel handles all system calls just like it would for any other userland program, as qemu seamlessly translates syscalls made by the guest to the host.

This, in conjunction with chroot, allows one to execute an entire OS made for an ARM CPU on an x86 computer seamlessly, with an enormous performance penalty but one dramatically lower than full-system emulation with an emulated ARM kernel would be.

Although Minki was the one who originally suggested this to me, it turns out that this procedure is well documented on the Debian Wiki for the purposes of modifying a Raspberry Pi image… Which is almost exactly what we’re doing!

A diagram that demonstrates the above workflow graphically.
A nice diagram made by a colleague to help present this subject. Thanks, Eliot!

From there building Dolphin was a matter of trial and error, and iteration could occur between hardware and the emulator with ease by simply moving the SD card the image was stored on back and forth. I found that the version of GCC included with Debian Bullseye was too old, so I updated one version newer to Debian Bookworm. Then, it was necessary to find the correct build flags for a generic Dolphin image. Here they are, at the time of writing:

cmake .. -DENABLE_GENERIC=true -DLINUX_LOCAL_DEV=true -DCMAKE_CXX_FLAGS=-march=armv6k -DCMAKE_C_FLAGS=-march=armv6k -DENABLE_QT=0

It was then possible to build Dolphin. Even on a 16-core, 32-thread Ryzen 9 3950X, it still took an hour and a half to compile using GCC inside qemu.

An image showing a task manager and a terminal below. The task manager shows all 32 threads of a Ryzen 9 3950X at 100% usage. The text below shows Dolphin source files being compiled.
“Yo dawg, I heard you like emulators, so I built you an emulator inside your emulator so you can emulate inside your emulator”

Then came the process of bringing up TigerVNC. Hilariously, this works perfectly fine inside qemu; the TigerVNC server can be spawned inside the chroot and connected to from anywhere. I now present the worst possible way to run glxgears:

  • Inside an emulated GPU (llvmpipe)
  • Which is run inside an emulated ARM CPU (qemu)
  • Which is sent over VNC, coming out of an x86 desktop with translated system calls for networking
  • Over the internet, via Tailscale, to another x86 laptop.

This gets 23FPS on my Zen 2 desktop.

Bringing it together

Dolphin is an immensely flexible piece of software, but in the end it still required some changes to boot.

First, the audio subsystem crashed. This can be disabled using a tricky-to-find command-line flag.

Second, there is a hard dependency on libusb for the official Nintendo GameCube Adapter drivers. Unsurprisingly, if there are no USB controllers present in the system, libusb returns a fatal error. After months of effort, ripping out the adapter code was the only source code change necessary for the gacube emeleter in its current form. This statement is an incredible testament to how flexible a piece of software Dolphin is.

And after all that, the dream is close to being fulfilled:

A Nintendo 3DS displaying command-line text.
Text version of the display
pi@3ds-debian:~ $ cat /sdcard/
/home/pi/dolphin/build/Binaries/dolphin-emu-nogui -v Null -a HLE -p headless -C Dolphin.DSP.Backend=No\ Audio\ Output /sdcard/sunshine.iso
pi@3ds-debian:~ $ /sdcard/
sh: 1: xdg-mime: not found
Dolphin 5.0 | Cached Interpreter DC | Null | HDLE | GMSE01

For the first time, a Nintendo 3DS is executing the first lines of code of Super Mario Sunshine6, a title made for the Nintendo GameCube.

What’s Left?

I took the above photo in December 2023, on one of the last days I had before being separated from my 3DS for the next five months.

The astute reader will notice that a frame has not actually been drawn. This is true. The more astute reader will notice that the graphics backend has been set to “Null”. This is also true.

Currently, it seems that Dolphin manages to crash llvmpipe somewhere when attempting to initialize an OpenGL context using it. This is reproducible both in the emulator and on hardware (I tested using a Raspberry Pi 1.)

A beta reader actually managed to dig up exactly what’s going on here. Apparently, Raspbian Bookworm ships a completely broken LLVM. The blog post that discusses this issue is only a month and a half old, so hopefully now that the issue has been identified it will be cleaned up.

Another obstacle is setting up a TigerVNC server and client on the 3DS itself. The server should perform the same. The client will need some significant scripting and hackery to display correctly. Perhaps I could place it on the bottom screen, since the 320×240 resolution on that screen is exactly half the GameCubes resolution.

And finally, a major concern with the whole stack is keeping RAM usage in check. Recall that the definition of Turing Completeness guarantees computation given unbounded time and memory. The New 3DS has 256MB of RAM, and we will need every last byte of it to make this work. Although swap is enabled and works, it will massively slow down this already horrendous process or kill it outright by breaking the SD card. The Dolphin devs and I were able to dramatically cut down on Dolphins memory usage for this configuration during a conversation at 37C3, but we figure right now it will still need 150MB. llvmpipe, a VNC server and a VNC client will need to fit in the rest, or at least come close.

Today, though, I can share the nearly complete gacube emeleter, built at long last years after it was demanded of us. Peter, if you’re out there, you can now rest easy.


  1. At this point in the 3DS hacking “scene”, one could access the powerful boot-time exploit called “arm9loaderhax” (explained in this talk at 32c3, the slides can be found here) if they were able to access the console-unique “One-Time Programmable” data, or OTP. The OTP is usually in a region of memory that should never be read… But fortunately, version 2.1 of the 3DS firmware did not lock it. So by performing a (lengthy) downgrade procedure to version 2.1, one could retrieve the OTP and install A9LH which provided boot-time code execution.
    You must use YOUR OTP to install A9LH, as the exploit depends on console-unique data. And because the exploit is boot-time, if for some reason it fails there was no hope for recovery. In Peters case, he used the wrong OTP, and the exploit indeed failed and bricked his system. ↩︎
  2. “no coffei” and its further misspellings were never fully explained. They were inserted at random into otherwise (relatively) legible statements. This also predated the infamous “covfefe” tweet by Donald Trump. It was a wholly original statement and thus became Peters catchphrase. ↩︎
  3. GBATemp is a fairly toxic place. As such, my quality of writing significantly suffered during my time there. I encourage people not to take my words in this archive too seriously. After leaving the forum in 2017, I re-learned how to speak to others on the internet. ↩︎
  4. A misspelling of obligation. ↩︎
  5. Dolphin opens a file descriptor to /dev/fb0 and then, as far as we can tell, never does anything with it. The m_fb_fd member variable is never used again. ↩︎
  6. Dumped from my own copy. Mario Sunshine continues to be the best 3D Mario game. Fight me. ↩︎






One response to “gacube emeleter”

  1. Dan Avatar

    Holy shit, hi! It’s Dan, if you remember me. Bumped into this site while looking up stuff on Itanium and actually belly-laughed when I read the domain.

Leave a Reply

Your email address will not be published. Required fields are marked *