Skip to the content.

My DIY FPGA board can run Quake II (part 2)

22-mar-2026

Backstory

I was already familiar with FPGAs. About ten years ago, I bought a board with Cyclone IV and tried to write my own processor in Verilog. It had a “unique” architecture that was completely incompatible with anything else on Earth.

But that’s a story for another time. This current journey began two years ago when I remembered that old project. In a sudden burst of nostalgia, I decided to try something in that spirit again.

However, this time I had an idea to build the hardware with my own hands. Not as far as etching the PCBs at home, but I was determined to do the soldering myself.

My previous soldering experience dated back to my school days. The peak of my achievement back then was working with microcontrollers in DIP packages. I remember a failed attempt to build an AVR programmer (which involved a single SOIC chip, if I recall correctly). Looking back, the 60-watt “fire stick” I found in grandfather’s toolbox was probably poorly suited for fine electronics work, but for some reason, it never occurred to me to find a better tool back then.

First attempt

Planning

First, I had to decide what I can and what I can not do. Unfortunately FPGAs are not available in DIP packages. I decided that soldering a QFP with a 0.5mm lead pitch was a risk I could take.

BGA, however, felt completely beyond the realm of reason (spoiler: a year later, I would eventually cross that line anyway, but at the start of the project, it felt like an impossible goal).

The problem is that almost all “serious” high-performance chips only come in BGA packages. Instead of pins sticking out from the sides, the contacts are tiny balls of solder hidden underneath the chip’s entire bottom surface. If something goes wrong during the soldering process, you can’t even see the mistake, let alone fix it easily.

Avoiding BGA packages narrowed my choices significantly. The largest non-BGA FPGAs I could find were the Altera MAX10 (10M50SAE144 and 10M50SCE144) with 50K logic cells. I settled on the 10M50SAE144C8G and bought two – I already suspected that I will not succeed from the first attempt.

To reach my goal of “building a computer” I needed RAM, storage, and interfaces for a screen and keyboard.

I threw in some LEDs, buttons, an I2C DAC with an amplifier for sound, and an Ethernet port (which I never actually used – I had enough problems without it).

I heard that for power stability there should be capacitors between VCC and GND, so I added a couple. (Spoiler: I should have researched this topic more. My board would later reboot itself whenever I plugged or unplugged a USB device).

After three weeks of learning KiCad, I finished my first design. I ordered the boards from JLCPCB and was impressed to find that five PCBs, including shipping from China, cost less than a pizza from the place down the street.

The first prototype, 3d model in KiCad

Of course, I was hoping for success on the first try. However, I had a feeling that I was attempting too much for my level of experience and that I would encounter every possible problem.

To prevent the undebuggable “it just doesn’t work at all” situation, I took a few precautions:

Time to pick up the newly purchased hot air gun and…

Many pins of the FTDI chip are bridged. Apparently I applied too much solder paste. Or maybe the hot air gun was not the right tool for this task. Though I suspect with my skills at this point it wouldn’t be better if I took a soldering iron and tried to precisely touch each pin one by one. Anyway, it’s a good thing this was not the main board.

The second try went better. Upon connecting it to the computer, it was recognized as an FTDI device. Success!

This time, the solder bridges appeared on the FPGA. GND and VCC were shorted in multiple places. The FPGA is the most expensive component on the board, and I only had two in stock. Now, I’m down to one. No matter what I tried, I couldn’t clear the excess solder. The only thing this board was good for now was testing the power delivery.

Actually, the power didn’t work either.

As it turns out, it is required to pull the CC1 and CC2 pins in a USB-C connector to GND through 5.1k resistors. Only then will the power adapter (in this case my laptop’s charger) believe that something is connected and provide 5V to VBUS.

Expectation: I spent three weeks designing. It looks like a serious PCB. I’ll solder it, and everything will just work.

Reality: On day two of troubleshooting, I finally figured out how to get 5V out of a USB-C connector. Yeah!

Right after that, it turned out that U7 (the 3.3V DC-DC converter) was soldered on backward.


U7’s top is the longer line, not the “U7” letters.

The next self-inflicted problem turned out to be the AP2114H 2.5V linear regulator. The full part number I used was AP2114HA-2.5TRG1. I assumed that the extra letters at the end were just minor variants that wouldn’t change much. I was wrong. It turns out that the “A” after the “H” stands for “Alternative pinout”. I had to place yet another order for components and, on this occasion, for extra soldering tips and a magnifying glass.

My second attempt at soldering the FPGA went much better. At the very least, the power rails weren’t shorted to ground. After a full day of meticulously poking each of the 144 pins with a multimeter and a soldering iron back and forth, the chip finally started responding to the programmer via JTAG.

And then – after fixing yet another floating pin – I finally managed to make an LED blink.

Looking at the damaged trace on the PCB after two attempts to solder an HDMI connector.

The HDMI stage did not go well. While soldering the connector, I managed to bridge a 0.25mm gap between two pins with a tiny blob of solder. In a desperate attempt to fix it, I poked at the bridge with a 400°C iron, only to drive the solder deeper into the connector housing without actually clearing the short.

The situation went from bad to worse when I tried to desolder the connector with a heat gun and ended up lifting a trace.

Eventually, I managed to solder on a spare connector, replaced the ruined trace with a bodge wire, and finally sat down to write the initial Verilog for the video controller.

And then Quartus, the IDE for Altera FPGAs, said this to me:

It turned out that I couldn’t just use any random pins for the HDMI output. In hindsight, I should have written a test project and tried to generate FPGA bitstream before designing the PCB layout.

I soldered another wire to a different pin that was intended to be GPIO. Didn’t work. The monitor just said “No Signal”.

And yeah, it unexpectedly turned out that the JTAG programmer was physically blocking the HDMI port. I couldn’t have both plugged in at the same time. This turned the debugging process into a tedious ritual: plug in the programmer, flash the internal memory with a new design, unplug the programmer, plug in the HDMI cable, power it up via USB, and wait to see… “No Signal” again.

For the next prototype, I made a note to keep the video traces short, straight, and isolated from other high-frequency signals.

DDR1 didn’t work either. I suspect that looking at my PCB traces a person with relevant experience would instantly say that it couldn’t work. And even later on the next prototype tuning IO constraints and debugging memory controller took me months.

However, I finally got a win: SD card reading actually worked! It took a couple of weeks of tinkering, but I successfully integrated the ZipCPU/sdspi controller. I just had to migrate the Xilinx-specific frontend to Altera DDR IO primitives.

The first prototype at its end of life

Intermediate results

What worked:

What didn’t work:

Audio didn’t work right away either, but I didn’t spend much time on it – I was already eager to start the second prototype using everything I’d learned. I also pushed the USB 1.1 implementation to a future phase.

Next part: Now it mostly works (3/6)