The Doom-chip "On Ice": designing hardware for a 1993 retro-classic
What would have resembled a console hardware dedicated to our beloved retro-games from the early 90's, such as Doom 1993 and Comanche 1992? I invite you on a journey to answer this question, not using emulation, not using a micro-controller, but designing our own hardware running on an entry-range ice40 UP5K FPGA, using a fully Open Source toolchain.
We'll dive into the rendering technology of the era, which was not polygon based in the traditional sense but rather based on clever tricks akin to ray-casting. We'll see what parts are critical to accelerate and how to achieve that in a limited gate-count (< 5K LUTs), while still reaching 320x240 pixels realtime rendering with full resolution textures.
The result fits entirely into the FPGA and its accompanying SPI-flash chip, and uses a low-cost SPI-screen. This turns your dev boards into a fantasy retro-console.
So buckle up Marty, we're going back to the future to re-invent the GPU!
I started the Doom-chip project from a simple question: What could have been a hardware version of our beloved retro 1993 classic? Little did I know that this question would take me through a fascinating journey in hardware FPGA design, going back to the very roots of how computer graphics are made.
From an initial focus on Doom alone, the project evolved towards creating hardware (on FPGA) dedicated to 3D games of that era -- a fictional 1990 console. Its GPU accelerates critical parts of the rendering, relying on a texture sampler streaming texels from SPI-flash. Around it I designed a simple SOC equipped with a dual-core compact RISC-V core and a SPI-screen driver -- all custom designs written in the Silice HDL (transpiles to Verilog). The whole thing fits in less than 5K LUTs on a low-cost, low-power ice40 UP5K FPGA for which several open-hardware boards are available (e.g. the IceBreaker). This leaves 128KB of SPRAM for the firmware, which is written in C. The main demo is a Doom-Comanche crossover, but many other games are possible.
It took me two years (roughly) to get to the current result. This was a bumpy ride: I took wrong turns, faced dead-ends, and had to restart from scratch. Along the way, I learned many lessons about the tradeoff between hardware and software that I'd like to share. And the project is not over yet!
With this talk I would like to share this journey, the excitement and enthusiasm resulting from designing your own hardware, from exploring a 3D world with it, from understanding how every single color bit forming the image on screen is actually generated, from scratch.
I will demystify the apparent complexity by going back the the very basics of how such games draw images on screen. The common denominator I found between these rendering engines is that they can be understood as drawing vertical columns, textured differently. For instance the Doom 1993 engine can be revisited (rewritten, really!) to draw only vertical columns of walls and floor/ceiling (flats). The perspective transform required to draw the flats is then very similar to what a terrain ray-caster requires, making terrain rendering ala Comanche 1992 a small addition.
I'll show how individual pieces of the hardware are created and composed together, and that each are actually *small* hardware designs:
- A SPI-flash, read-only quad-speed controller (~ 120 lines)
- A hardware column drawer for floor, walls, terrains (~ 400 lines)
- A dual-core RISC-V RV32IM CPU (~ 250 lines)
- A SPI-flash screen driver (~ 50 lines)
- A global unit plugging all these components together (~ 300 lines)
That's quite compact in terms of code, and it synthesizes to less than 5000 logical elements on the Ice40 UP5K FPGA. I'll describe the overall architecture, the design choices that were made and why. The talk will be accessible to non experts (overall architecture and graphics algorithms with plenty of illustrations), but will also contain enough details to be engaging to those who understand hardware design (anectodes, gritty details, deep dive in a few aspects). I'll also share a ready-to-be-flashed bitstream and explain how to create your own levels for the Doomchip-On-Ice, using the Slade editor, so that everyone can start hacking!
Beyond the design itself, I'll share some fun hardware-design related anecdotes, like when I ended up diving into Yosys DSP synthesis to understand why my multpliers wouldn't work, how I used UART to enable 'printf' debugging of my design, how I realized you can't have a dual-core CPU and a single stack, and how I almost lost my mind debugging timing issues on SDRAM, to later abandon SDRAM entirely! More importantly I'll explain how to better approach these issues in hindsight.
I believe rC3 is the right forum to share this project and I hope to encourage others to dive into similar endeavors. This is about having fun and getting a deeper understanding of the gaming platforms we use and what they truly are: an extremely fast and intricate network of gates and flip-flops that can lure you in believing you are exploring a 3D world.