Hacker News new | ask | show | jobs
by lopis 886 days ago
Reminds me of that meme that says

> Look What They Need to Mimic a Fraction of Our Power!

That tiny arduino has a 16Mhz chip, while the NES main CPU ran at 1.66 MHz. Just a funny fact :)

4 comments

In that case, you’ll love tom7’s Reverse Emulation video: https://youtube.com/watch?v=ar9WRwCiSr0
You're totally right. I loved it, thanks!
I once designed a custom PCB that fits inside the original NES four score case. You can connect 4 NES controllers to it and the inputs were sent to a Raspberry Pi via UDP (so no wire between couch table and TV was needed).

I think my PCB had more parts for its simple power supply than all 4 NES controllers combined.

These things are an absolute masterpiece of simplicity!

My coworker has done a similar thing, designing a PCB that allows us to connect the SNES controller over RJ45 to a custom Pi hat. We have students writing bare metal code for it!
SNES can go up to a whopping 3.58Mhz (NTSC clock, not sure if exactly the same for PAL) but I believe due to some bus/architecture weirdness slows down to 1.79Mhz (which is what the NTSC NES runs at) when reading the controllers.

Now the SuperFX chip, in Star Fox, ran at 10Mhz. Later versions like the one in Doom on SNES went up to 21Mhz.

That 16MHz of processing power is doing a pretty magical thing, though. It's encapsulating what is basically a serial bus, into a universal serial bus — i.e. it's making it so that:

• you can plug this controller into any USB host, and the host can probe the device and discover that it's got a USB HID gamepad device

• the SNES buttons get mapped onto standard USB HID event codes (HID Usage IDs), such that you could have a SNES controller plugged into one USB port and a Sega Saturn controller plugged into another USB port on the same computer, and they'd both be using a common language for events like "D-Pad Up button pressed", such that a framework like DirectInput or SDL can understand that out of the box. The SNES just uses the same 16 bits of input register no matter what's plugged in (gamepad, mouse, super scope, etc) — with games either assuming a specific static input device type and thus parsing those 16 bits in terms of that; or telling you to have a gamepad on P1 and whatever on P2, and then asking you on startup what type of thing you've got plugged into P2.

• And — not so applicable to the SNES — but with USB, you can also have more than one of any given HID Usage ID reported by the same device. A gamepad with two analogue sticks can† just report analogue data for X/Y/Z-axis Usage IDs twice.

• You can also have as many USB HID gamepads plugged into the same host machine at the same time as you like†. Even USB 1.1 is a very fast bus compared to the SNES's input polling rate; tons of HID reports will "fit" down the pipe as packets. The SNES, meanwhile, fundamentally only supported four input devices at once, because the hardware had exactly 64 bits mapped starting at $4218, representing the 16-bit readouts from polling of up to four input devices. And even then, if you wanted all four inputs to be polled, then you'd only be getting input for devices 1+3 refreshed on even frames, and 2+4 polled on odd frames.

• You can have tons of other things — more data-intensive things! — plugged into the USB bus at the same time as the gamepad, and it'll still work just fine, because USB HID reports are given high QoS by USB host controllers and hubs. The SNES needs a separate bus for the cartridge, but on a PC the equivalent of a "cartridge" (an eGPU + eFPGA + NVMe, let's say?) could be connected to a USB4 dock, that your gamepad is also plugged into — and a single USB cable will take all that into your computer.

• You can hotplug USB devices, without confusing either the client input device or the running program on the host. Both sides of a USB link (well, assuming the client retains power when unplugged) have knowledge of the connection lifecycle state. "Device unplugged" or "device plugged in" or even "a new, second device plugged in" are just like any other gamepad events, that your game can have a handler for. Meanwhile on the SNES, both input ports are just assumed to be populated at all times — and are therefore electrically live‡ and receiving a polling clock at all times. The distinction between there being 1/2/3/4 input devices connected, has to be made manually, by the game asking. There's no way for the game to know that a device was plugged/unplugged.

---

† Consumer OSes mostly don't like this — but that's because consumer OSes are dumb, and have to this day never surfaced a high-level "gamepad API" that actually exposes the full extensibility of USB HID reporting.

A high-level API that was actually designed to reflect the HID spec, would have an input-event report be a dictionary where the keys are usage IDs and the values are arrays of sensor readouts. Or a stream of polymorphic Usage-ID-keyed sensor-readout records. And either way, each report would at the very least identify which USB device it's coming from, so that you can tell apart reports from two identical controllers.

But instead, what most gamedevs get from using industry "best practices" when writing an app-game using e.g. DirectInput or SDL for input, is an API that's even more naive than the SNES joypad input registers — it assumes that there's exactly one gamepad, and that it's reporting exactly one of each HID Usage ID. (And even worse with XInput, which assumes a fixed set of Usage IDs corresponding to "what an XBox controller has!")

As such, most USB HID gamepads sold to consumers for use with PCs, in practice, don't take real advantage of what USB HID gamepads can in theory report.

USB HID gamepads made to be used in proprietary ecosystems, on the other hand — think "the Nintendo Switch Pro controller" or "the input board on an arcade machine" — are free to be designed to actually use USB HID correctly. Which is why such devices usually need special drivers on PCs. They're not speaking a brain-damaged wire protocol; rather, they're living in the present and taking full advantage of USB HID features... while consumer OSes are still stuck in the past, unable to cope. :)

This is also why so many systems like emulators that support these proprietary input devices — or games complex enough, that they expect USB HID devices that are themselves complex enough to only be possible if using the spec the modern way (think, uh, this thing: https://www.amazon.ca/Logitech-Saitek-Vehicle-Panel-945-0000...) — just skip the high-level gamepad-input-handling frameworks, and just register to listen to USB HID events directly. Because that's the only level at which they'll receive the information they actually care about, without the OS first mangling it into incomprehensibility.

‡ I believe polling for the input ports get zeroes rather than garbage if the ports aren't connected — but this is likely more for hardware protection than anything else, with pulldown resistors on the read path to prevent you from shorting out the input pins by unplugging while the console is on. Nintendo at least learned the lesson of the PS/2 bus.)