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...

Code: https://github.com/jkirsons/Doom


Development Environment

At this stage I was using PlatformIO + VSCode as my development environment.  It was easy to initially setup, but I quickly hit limits using PlatformIO.

PlatformIO didn't give me the ability to run "make menuconfig" where you can directly change lots of memory/spi/rtos related settings.

My next step was to install the full ESP-IDF toolchain:

https://docs.espressif.com/projects/esp-idf/en/latest/get-started/

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.

Here is the result:

Code: https://github.com/jkirsons/OpenTyrian

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.

I found this: Chocolate Duke Nukem 3D
http://fabiensanglard.net/duke3d/chocolate_duke_nukem_3D.php

Duke Nukem 3D

So I stated at getting Duke Nukem 3D to compile on the ESP32.

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:

So now I had Duke Nukem 3D compiling and running on an ESP32!!!

Code: https://github.com/jkirsons/Duke3D

The next level - ODROID-GO

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,...

Read more »