Close
0%
0%

FPGA Doom

Porting the classic Doom engine to an FPGA-based system

Similar projects worth following
This project builds on my Bexkat1 CPU project, with the goal of porting the classic Doom game engine in playable form. It's a great platform to evaluate hardware design changes. Obviously the image samples shown here are from the non-public WAD file and are for illustration. You can buy the game and get the WAD file GOG as well as many other places.

CPU project is at https://hackaday.io/project/8716-bexkat1-cpu

I'm using the WAD file from Ultimate Doom on GOG. The build process is pretty simple, but requires that you have the full GCC, binutils, and newlib tool chain, as well as the bexkat1 source. The bexkat1 source is needed only for the support library that is currently in there - there are some things that I do that are not part of newlib and so don't fit perfectly yet.

  • More Speed

    Matt Stock12/11/2016 at 02:00 0 comments

    As with all good hobbies, I went on a couple of tangents recently. While I was waiting for the new daughterboard, I decided to spend some time on speed improvements.

    The first step was the easiest: I just doubled the clock speed from 50MHz to 100MHz. The external memory (SDRAM and SSRAM) had plenty of headroom, and I took the opportunity to parameterize all of the modules that use their own clock (SPI, I2C, UART, etc). That helped, but not enough. The memory operations were just too inefficient.

    The next step was to add simple write FIFOs for memory modules. The idea here is that writes can return immediately because the CPU isn't expecting a response. If the CPU makes a read request, that read will stall until the write FIFO is empty, ensuring that there is consistency. I put this FIFO between the CPU and the memory controllers so that it woudl do the most good. It helped, but wasn't a game changer.

    As most of you probably already know, SDRAM isn't particularly efficient at single word operations. You need to "open" a row of memory, do some operations, and then "close" it again. The overhead of the open and close operations is huge when you only do a single read or write, which is what I was doing up until this point.

    By adjusting the cache memory system and the SDRAM controller, I was able to to enable pipeline operations, making memory access a lot more efficient. Since I already had the cache controller handling 4 words in a cache line, it wasn't particularly hard to enable a 4 word pipeline. The nice thing is that all of this is abstracted away from the CPU - it can still use single word operations and gave some of the benefits simply because the content gets into the cache memory more quickly. This and increasing the cache size to 4k words (from 1k) made a substantial difference in performance. I'm starting to use the Doom load time as my benchmark for these things, and I've now got it down to about 1m20s from program load to menu.

    There are so many additional optimizations that I can still apply:

    • Block memory transfer CPU instructions
    • Improving the SDRAM controller to keep rows open longer and increase the time between refresh cycles
    • Improve the SSRAM controller to handle burst operations (should help with frame rate)

    I may tackle some of these in the near future.

  • New stuff

    Matt Stock11/17/2016 at 21:13 0 comments

    I know it's been a while since I updated this project. I'm better at working on the projects than documenting them. I've been focused on some other projects for a while, but now I've got some time and renewed interest, so expect updates soon.

    I just finished spinning a new IO board for this project. It's a simple one that incorporates an RTC chip, a codec with line in/out and headphone out, PS/2 keyboard, and an aux output for the LED matrix. I've been working on an i2c master instance for my SoC, which I can then use to program the codec. Untimately, I want to use the codec to serve as an output for the PCM/WAV audio for the game. So next update will talk about the audio interface and progress on integrating the audio into Doom.

  • Cache and new codec

    Matt Stock01/03/2016 at 20:57 0 comments

    I picked up the Adafruit Codec module recently, and I'm working to integrate it into the system design. It's SPI based and understands how to process both MIDI and WAV, and so I'm hopeful that I'll be able set this thing up to play sound effects and music from Doom without a lot of pain.

    Read more »

  • Video Demo

    Matt Stock12/11/2015 at 03:22 1 comment


  • Detailed VGA controller description

    Matt Stock12/11/2015 at 03:19 2 comments

    As I mentioned earlier, the VGA controller was an interesting part of the design for me. While not perfect, it addresses my immediate needs, and there are several opportunities to tweak the design. For example, right now the 320x240 double pixel mode is hardcoded, but this could easily be added to a control register to all the CPU to change the video mode as needed.

    Here's a block diagram of all the major parts:

    Read more »

  • System Block Diagram

    Matt Stock12/11/2015 at 02:55 0 comments

    Here's a high level view of the overall system architecture:

    Read more »

  • Custom Video (or the power of FPGA)

    Matt Stock12/09/2015 at 16:27 3 comments

    There are a lot of howto articles about building VGA clocks in FPGAs. My favorite is the Pong Game. More complex for me was how to take that VGA clock and use it to build a true framebuffer for a CPU. This introduces two new challenges related to memory bandwidth and multiple clock domains. I'll describe how I implemented my framebuffer in Verilog in a later article, but here I thought I'd share one of the interesting things I did when porting DOOM that was made trivial on an FPGA platform.

    Read more »

  • It Works!

    Matt Stock12/09/2015 at 04:25 0 comments

    I have the basics down - the program will load, load the WAD file, render the player views. Controls are crude, but I was able to map some of the keyboard commands to the analog joystick and pushbuttons to get things tested. I have a Doom on FPGA video up on Youtube.

    Some next steps:

    Read more »

View all 8 project logs

  • 1

    Install the GCC, binutils, newlib binaries following the project instructions.

  • 2

    Clone the Bexkat1 repo and run "make" in the soc/monitor directory.

  • 3

    Clone the DOOM repo, and edit the bexkat1doom/Makefile to refer to the soc/monitor/include and soc/monitor/library paths from step 2.

View all 6 instructions

Enjoy this project?

Share

Discussions

Brett Weir wrote 09/24/2016 at 06:27 point

This is super awesome!

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates