Description

There's a video of DOOM running on the ESP32, so I wondered if I can get this running myself?

This led me into trying out what other games I could get running on it... If it can run games that a 486 could, there should be plenty of others that will run on it too!

Details

This project details my efforts in experimenting with running games on the ESP32, and porting new games to it.

I started off with an ESP32 WROVER DevKit, added an SPI LCD screen (type ILI9341), SPI SD Card slot, amp + speaker, and a few buttons. Using an ESP32 WROVER is important, because the WROVER contains 4MB ram - which is essential for running games. Now I had everything I need to start running games.

DOOM

I started off trying to run DOOM. But it used the onboard SPI Flash to hold the game data. An ESP32 only has a max of 16Mb spiflash - which means that this would be a limitation to what games could be run, and how easy is is for others to run these games.

So my first task was getting DOOM to run from the SD Card - this was a fairly easy swap.

Also I added back in the code to have sound working, and modified it to use the i2s sound output. The ESP32 can internally connect the i2s output to it's DACs, so it can directly product sound output, it just needs some amplification...

This let me unlock lots more potential from the ESP32, and gives valuable debug tools (including backtrace code address resolution). The good this is, I can still use VSCode as my IDE.

If you're using Mac or Linux, you can even compile/monitor/menuconfig directly from a terminal in the IDE:

OpenTyrian

My next step was to port a new game over to the ESP32 - one that no one has ported yet. So what game has been ported to nearly every platform? Tyrian!

OpenTyrian has the advantage that nearly all the platform dependent code (ie video, sound, input, disk) has been removed, and handled by one library. That library is SDL (https://www.libsdl.org/).

I ended up making my own "mini" SDL library for the ESP32. I call it mini, as it only implemented the functions that OpenTyrian needed. The screen writing code was used from Doom (ie flipping a memory array (SDL Surface) to the screen), Input events re-written to use GPIO inputs, sound re-written to use i2s sound output, and initialisation of the SD Card before any disk I/O calls.

Alright, I've ported my first game! What's next? I have a partial SDL 1.2 library that can make porting the next game a bit easier, so I just need an SDL port of an old classic DOS game that would run in an early 486.

My first problem was memory. Duke Nukem 3D had lots of (large) arrays. An array takes up DRAM, of which the ESP32 only has around 290kb. The 4Mb SPI RAM can only be used by malloc() calls. OpenTyrian was ok because there were not too many arrays, but Duke Nukem 3D has lots of arrays.

At this point, I found in one of the later ESP-IDF releases, an attribute was introduced that lets the array be allocated in SPI RAM instead of DRAM. It is EXT_RAM_ATTR - and I used this a lot:

OK, now I have proven that I old DOS games can be ported to the ESP32, it's time to take it to the next level. The breadboard works, but if you wobble things too much it might crash, and most importantly,...

Absolutely incredible work! This is so neat. I'm just about to start tinkering with the ESP32 and it's neat to see what it can do. What made you choose to use FreeRTOS instead of programming it by hand? Just time-saving?

That's right, all the videos are the ESP32 natively running games that were recompiled for it from source code - it definitely is not emulating x86 architecture. I was just meaning that the 240Mhz ESP32 is not going to run a game that has minimum requirements of a modern PC.