aSMtris - Tetris in assembly language (x86, 16-bit)
After completing an C#/XNA game project, I really wanted to delve down to the metal again, and what better way to do so than with assembly language? I wrote my last assembly program back in 2000 (it was a Nibbles-like attempt), but did not actually complete it. Fourteen years later, I decided that writing a game in assembly language was a loose end that had to be tied.
aSMtris continues to be updated with new features in the version for my Snowdrop OS operating system.
Visit the Snowdrop OS pages to find out more.
Note: I've noticed the flickering that can be seen in this video only in the DOSBox emulator, and not on actual hardware.
The aSMtris executable is very small in size, at nearly 2 kilobytes. Comparatively, it takes up the same space as a tiny, 50 by 50 pixel JPEG image. The difference, of course, is that the 50 by 50 pixel JPEG image is nearly useless (possibly making a good icon, and that's about it), whereas aSMtris is a full game.
That being said, for the same amount of space, 2 kilobytes, you can play Tetris, or you can stare at the crappy image below:
aSMtris will run out of the box in Windows XP and earlier, including, of course, MS-DOS. For later operating systems, download the free DOSBox emulator which will run aSMtris without problems.
source code - the single-file aSMtris source code
executable - the MS-DOS .COM executable. Use with Windows XP or older, or with the DOSBox emulator
dev kit - aSMtris source packaged with the NASM assembler, and a simple make batch file
Keeping everything in one source code file just seemed right when dealing with assembly language. It's a large file, but that's because about 85% of the contents are comments, and the other 15% is the actual program. Since this is as far away as you can be from self-documenting code, I've never before written so much documentation per line of code. No fancy tools were used; just Notepad++ and the NASM assembler. Development took about four weeks.
One aspect I found very interesting is the types of bugs I encountered and squashed during development. They were unlike those you'd expect to find in programs written using high level languages, both in nature and in how they manifest.
The first example is a bug which sometimes caused pieces to go through other pieces and through the walls, but not always. It took me about thirty minutes to find and fix it, and the fix was changing a 2 to a 1. What I had meant to do is multiply a register by 2, which can easily be accomplished by shifting its bits to the left one position. Due to my carelessness, I shifted by 2 bits, effectively multiplying by 4.
Now, in my day to day development I use short-circuiting out of loops whenever I can. As soon as I tried it in assembly, I wrote a bug. I was writing two nested loops. Both used the x86 instruction "loop", which meant that both used register cx as a loop counter. This, of course, meant that whenever entering the inner loop, cx had to be pushed on the stack, and then popped off the stack when the inner loop was left. My mistake was that I was jumping (short-circuiting) out of both the inner loop and outer loop, but left an extra value on the stack. Needless to say, not a fun one to debug.
In terms of bug manifestations, they varied from the screen becoming corrupt and crazy, to the internal speaker beeping uncontrollably, to the program simply crashing immediately after starting.
aSMtris was a really fun project because of the inherent pleasure to be had from knowing exactly what is happening at any point in your game code. Assembly language seems to be less and less relevant due to ever faster hardware, but take my word for it, it's very satisfying when you complete a project using it. When it works, that is...