aboutsummaryrefslogtreecommitdiff
path: root/posts/adieu-quake.md
diff options
context:
space:
mode:
Diffstat (limited to 'posts/adieu-quake.md')
-rw-r--r--posts/adieu-quake.md82
1 files changed, 47 insertions, 35 deletions
diff --git a/posts/adieu-quake.md b/posts/adieu-quake.md
index c167542..cc7a451 100644
--- a/posts/adieu-quake.md
+++ b/posts/adieu-quake.md
@@ -1,13 +1,18 @@
-# Adieu, Quake!
+% Adieu, Quake!
+%
+% 27 Aug 2019
-[![Quake on Rockbox](http://img.youtube.com/vi/74i8aBOmyos/0.jpg)](http://www.youtube.com/watch?v=74i8aBOmyos)
-
-![](quake.jpg)
+<center>
+<figure>
+[![Quake on Rockbox](https://img.youtube.com/vi/74i8aBOmyos/0.jpg){height=300}](https://www.youtube.com/watch?v=74i8aBOmyos)\ ![Quake on the iPod Classic.](quake.jpg){height=300}
+<figcaption>Quake running on an iPod Classic.</figcaption>
+</figure>
+</center>
**TL;DR** I made Quake run on MP3 players. Read how it happened.
I spent part of this summer playing with two of my favorite things:
-[Rockbox](https://rockbox.org) and id Software's
+[Rockbox](https://www.rockbox.org) and id Software's
[Quake](https://en.wikipedia.org/wiki/Quake_(video_game)). I even got
the chance to combine the two by porting Quake to run *on* Rockbox!
What more could I ask?
@@ -25,7 +30,7 @@ months, so I'm trying to get this brain dump in before the deluge.
## Rockbox
-[Rockbox](https://rockbox.org) is a fun open-source project I spend
+[Rockbox](https://www.rockbox.org) is a fun open-source project I spend
far too much time hacking on. The web page explains it best: "Rockbox
is a free replacement firmware for digital music players." That's
right, we provide a complete replacement for the manufacturer's
@@ -37,8 +42,8 @@ we support loadable extensions called *plugins* -- small programs to
run on your MP3 player. Rockbox already has a bunch of nifty games and
demos, the most impressive of which were probably the first-person
shooters [Doom](https://www.rockbox.org/wiki/PluginDoom) and [Duke
-Nukem 3D](https://www.rockbox.org/wiki/PluginDuke3D). But I still felt
-there was something missing.
+Nukem 3D](https://www.rockbox.org/wiki/PluginDuke3D).[^1] But I still
+felt there was something missing.
## Enter Quake
@@ -58,8 +63,9 @@ with CPUs as slow as 11MHz and as little as 2 MB of RAM (of course,
Quake wasn't going to be running on *those* devices). With this in
mind, I looked at my ever-shrinking DAP collection and picked out the
most powerful surviving member: an Apple iPod Classic/6G, with a 216
-MHz ARMv5E and 64 MB of DRAM. Nothing to sneeze at, but certainly
-marginal when it comes to running Quake.
+MHz ARMv5E and 64 MB of DRAM (the *E* indicates the presence of ARM
+DSP extensions -- this will be important later). Nothing to sneeze at,
+but certainly marginal when it comes to running Quake.
## The Port
@@ -84,10 +90,10 @@ avail -- the bug was too hard for me, or so it felt.
And so it remained, for years. I should probably give a little timing
information at this point. This first attempt at Quake took place in
-September 2017, after which I gave up. My Quake-Rockbox abomination
-sat on a shelf, collecting dust, until July 2019. By just the right
-combination of boredom and motivation, I resolved to finish what I had
-started.
+September 2017, after which I gave up, and my Quake-Rockbox
+abomination sat on a shelf, collecting dust, until July 2019. By just
+the right combination of boredom and motivation, I resolved to finish
+what I had started.
I got to debugging. Now, my flow state is such that I remember
virtually no details of what exactly I did, but I'll try my best here
@@ -119,7 +125,7 @@ gotten Quake to boot on an MP3 player!
## Down the Rabbit Hole
This project finally gave me an excuse to do something I'd been
-putting off for a while: learn ARM assembly language.[^1]
+putting off for a while: learn ARM assembly language.[^2]
The application was in a performance-sensitive sound mixing loop in
`snd_mix.c` (remember the lawnmower-like sound?).
@@ -178,14 +184,15 @@ SND_PaintChannelFrom8:
~~~
There's some hackery going on here that could use some explaining. I'm
-using the ARM `qadd` DSP instruction to get saturation addition for
-cheap^[1](#asm-listing-25)^, but `qadd` only works with 32-bit words, and the sound samples
-are 16 bits. The hack, then, is to first shift the samples left by 16
-bits; `qadd` the samples together; and then shift them back. This
-accomplishes in one instruction what GCC took seven to do. (Sure, I
-could've avoided this hack altogether if I were working with ARMv6,
-which has MMX-esque packed saturation arithmetic with `qadd16`, but
-alas -- life isn't so easy. And besides, it was a cool hack!)
+using the ARM `qadd` DSP instruction to get saturation addition [for
+cheap](#asm-listing-25), but `qadd` only works with 32-bit words, and
+the sound samples are 16 bits. The hack, then, is to first shift the
+samples left by 16 bits; `qadd` the samples together; and then shift
+them back. This accomplishes in one instruction what GCC took seven to
+do. (Sure, I could've avoided this hack altogether if I were working
+with ARMv6, which has MMX-esque packed saturation arithmetic with
+`qadd16`, but alas -- life isn't so easy. And besides, it was a cool
+hack!)
Notice also that I'm reading and writing two stereo samples at a time
(with a word-sized `ldr` and `str`) to save a couple more cycles.
@@ -225,7 +232,7 @@ will lead to an integer wraparound to `0xFFFFFFFF` and an extremely
long delay (which will eventually resolve itself).
This corner case was triggered by one sound in particular, of 7325
-samples in length.[^2] What's so special about 7325, you ask? Try taking it
+samples in length.[^3] What's so special about 7325, you ask? Try taking it
modulo any power of two:
$$
@@ -259,10 +266,11 @@ isn't it?
## Adieu
In the end I ended up packaging this port up as a
-[patch](http://gerrit.rockbox.org/r/#/c/1832/) and merging it into the
+[patch](http://gerrit.rockbox.org/r/1832/) and merging it into the
Rockbox mainline, where it resides today. It ships with builds for
most of the ARM targets with color displays in Rockbox 3.15 and
-later.[^3]
+later.[^4] If you don't have a supported target, you can
+[watch](https://www.youtube.com/watch?v=74i8aBOmyos) user890104's demo.
I've omitted a couple interesting things here for the sake of
space. There is, for example, the race condition that occured only
@@ -277,19 +285,23 @@ now, it is time to say goodbye to Quake -- it's been good to me.
So long, and thanks for all the fish!
-[^1]: If you're interested in learning ARM assembly, Tonc's
-[*Whirlwind Tour of ARM
-Assembly*](http://www.coranac.com/tonc/text/asm.htm) is a good (albeit
-slightly outdated and GBA-oriented) place to start. And while you're
-at it, go ahead and get a printout of the [ARM Quick Reference
-Card](http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf).
+[^1]: The latter game was the first to use the Rockbox SDL runtime and
+deserves a post of its own. Watch user890104's demo of it
+[here](https://www.youtube.com/watch?v=aEkBJ-fHxhA).
+
+[^2]: If you're interested in learning ARM assembly, Jasper Vijn's
+[*Tonc: Whirlwind Tour of ARM
+Assembly*](https://www.coranac.com/tonc/text/asm.htm) is a good
+(albeit slightly outdated and GBA-oriented) place to start. And while
+you're at it, go ahead and get a printout of the [ARM Quick Reference
+Card](https://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf).
-[^2]: It was the sound triggered by a [100 health
+[^3]: It was the sound triggered by a [100 health
pickup](r_item2.wav), incidentally.
-[^3]: I honestly don't remember exactly which targets do and don't
+[^4]: I honestly don't remember exactly which targets do and don't
support Quake. If you're curious, head over to the [Rockbox
-site](http://rockbox.org) and try installing a build for whatever
+site](https://rockbox.org) and try installing a build for whatever
target(s) you might have. And do [let me know](mailto:me@fwei.tk) how
it runs! New versions of [Rockbox
Utility](https://www.rockbox.org/wiki/RockboxUtility) (1.4.1 and