Do you like my hacking? If so, please consider leaving something in the
Fediverse (Mastodon etc): @Sprite_tm@social. spritesmods.com
As stated before, I'm building on the great work of whoever owns the Doomhack GBADoom repository; they did the bulk of the work needed to get Doom to run in 1/10th of the original memory. What I did to the engine mostly boiled down to ripping out the GBA bindings (display, input) and replacing it with my own.
One thing I did need to change entirely was the music. Rather than use the original songs, the GBA Doom port opted for re-imagined chiptune tracker songs, and it played this using some player routines written in ARM assembly. First of all, those would be hard to port to RiscV, and secondly, I wanted to hear the classic OPL version I grew up with. The original Doom songs are in .mus format, which is proprietary without a player lib available. They are also in an 'universal' song format, meaning that the specific music sound driver needs to do work to convert the instruments into whatever the sound hardware requires. Putting all that in the ESP32-C3 sounded like a lot of work.
Luckily, I found a way to sidestep all of that. I could take the MUS files (and the soundfont files, needed to play the MUS files on an OPL, like found in a Sound Blaster or Adlib) from the Doom wad using wadext, then convert them to .imf files using imf-creator. .imf files are a much simpler music format: they assume an OPL chip and simply contain OPL register writes and delays; implementing a player for this format is trivial. Obviously, the ESP32S3 does not have an OPL chip, but that's easy to fix: there are a fair few good OPL emulators out there, and I choose to use the one from the Dosbox project. The actual audio output is sent to an I2S peripheral in PDM mode, which is similar to PCM in that you can directly connect a speaker to it and it'll sound good. To get some extra amplitude, I configured one GPIO to output the PDM signal and another to output the inverse, so I can connect a speaker directly between those and get twice the volume. Again, this is very much not something you should do in a production environment as GPIOs generally aren't well-equipped to drive inductive loads, but given that I know that ESP32 chips generally have fairly robust GPIOs and this is not production hardware, it should be fine.
The other was the input subsystem. While the Doom bauble is interesting enough simply playing the demos, I really wanted to be able to play Doom as well. As I didn't want an actual input device hanging off of the thing, I used BLE for this: while it's a bit tricky to find a keyboard, mouse or joystick that is BLE-only and does not expect the host to have Bluetooth Classic, it's doable.
For this, I wanted to use NimBLE, a lightweight Bluetooth LE stack, as the alternative would use too much memory. To my knowledge, there isn't any clear example of using that to interface with HID peripherals (keyboards, mice, joysticks etc) yet, so I had to build that myself. Borrowing bits from FreeBSD's libusbhid and the NimBLE ble-central example, I quickly got to a point where in theory you can control Doom from any HID-capable BLE device: simply put it in pairing mode and the ESP32C3 should connect to it.