Last update: 16 Oct 2025
This blog is mostly about my interest in how older machines were programmed, the quirks of those machines, and how those quirks were worked around or exploited. A secondary interest, however, is in what the future can teach the past, or vice versa. Modern software architecture techniques may have parallels in 8-bit assembly language, and contemporary programs can benefit from falling back to more established techniques from more constrained environments.
This index is less about specific tricks on specific platforms—that sort of thing is organized by platform over with the Platform Guides—and more about general considerations when organizing software.
Famous (or Infamous) Techniques
That said, some specific tricks on specific platforms became so infamous that they turned into legends in their own right.
- Variable Screen Placement. The most infamous trick on the C64, and it got some modern interest after some high-profile game releases in 2019 made use of it. It gives the C64 NES-level horizontal screen scrolling, which it isn’t supposed to have. It also can cause memory corruption, and in 2012 the cause of that corruption, and how to fix it, were discovered. This article is just an overview; see the articles on “badlines” and “partial badlines” down in the Commodore 64 section for a full dive into the background.
- Extended-color CGA Modes. This is not the “1024 colors in CGA mode” technique introduced by the 2015 demo “8088MPH”, but it is instead the two half-supported extended-color modes that the 8088MPH technique was built out of. Both modes were known and used back when CGA was still relevant.
- Digital Sample Playback on the PC Speaker. The PC speaker was really only designed to make sharp, harsh beeps of various pitches, but by the early 1990s programmers had refined a technique to let it reproduce arbitrary sound waves, including human voices.
- Atari 2600 sprite positioning. Atari 2600 sprites are not particularly developer-friendly; they are placed by writing a special register that basically says “wherever the television’s electron gun is pointing right now, place the sprite there.” This article develops, and derives the principles behind, a 27-byte routine that will place a sprite at any X coordinate it is given as an argument. I have since learned that this general technique was also used in Atari’s 1983 port of Battlezone to the Atari 2600, so this was definitely a technique known back in the Atari’s heyday.
- A Grimoire of 8-bit Implementation Patterns. When people try to translate, rather than merely emulate, old 8-bit code, they often run afoul of many of the tricks in this article. Super Mario Bros., for instance, appears to have code that jumps into the middle of instructions, and it turns out that was a reasonable-enough thing to do on the NES that you could imagine making an assembler macro to manage it for you when needed.
General Programming Techniques
A lot of the basic machinery of modern programming that we take for granted started out as organizational techniques in less expressive languages. Some of those things eventually became common enough that they got hardware support. Others didn’t, but it’s worth knowing how they do what they do “by hand” when the need arises.
- Call Stacks. What it means to call a function in a systems-programming language has been stable for quite awhile now, but it didn’t used to be so. This article digs into the kinds of things the stack is used for, and various levels of hardware support for them.
- Object Oriented Programming. OOP spent most of the 90s and 00s being treated as an absolute hard requirement for any seriously intended programming language. This article builds an efficient single-inheritance OOP system in both C and 32-bit x86 assembly language, should you actually need this in code that isn’t written in an OOP language. An odd little followup talks about how the Go programming language attempted to discard OOP and reinvent it, the gaps this produced, how to close them, and ways to not have to.
- Functional Programming. FP is older than OOP, and it became faddishly trendy about the time OOP skepticism became mainstream. First-class functions are very nice, but what are they really, under the hood? This article breaks them down, links them to the OO system developed in the previous article as well as to idiomatic C API style, and determines the price that must be paid for the power they provide. (The answer: about one extra instruction per function call, on the 386.)
Sometimes lack of hardware or OS support for something stings harder, though. These articles cover cases where I work around specific limitations.
- Fixed-Point. Need fractional values? Don’t have a floating-point processor, and possibly not even hardware support for multiplication? Fixed-point math has you covered. Speedrunners talking about “subpixels” when describing the behavior of characters in early console games are contending with fixed-point geometry systems.
- 8-bit test cases. How do you test your clever new routines on hardware that has no text output, and sometimes no OS? This article focuses on the Game Boy, but I had to do the same trick again on the Atmel AVR later.
- A Grimoire of 8-Bit Implementation Patterns. What to do when your chip doesn’t have decent support for pointers, or exceptions, or conditional execution, and you’d really like to have those things.
- Content Creation. There are specialized tools, these days, for creating graphics for many classic platforms. But what if you ignore all those because you already have paint programs you like, and limitless tolerance for custom, janky command-line build/conversion scripts? This article is specifically about the NES, but the general workflow here also served me well when I was creating icons for my Amiga programs.
- 8-Bit Data Flows. Earlier CPUs often sharply restrict the number of registers available and what you can use them for, and this has implications for what kinds of basic programming techniques are actually intuitive or efficient on those platforms. This article compares the Z80 and 6502 in particular and highlights ways that they encourage different approaches to things like iterating through arrays.
- Memory Models and Far Pointers. Writing code for DOS—at least, until the early-to-mid 1990s when DOS extenders became the norm—often meant dealing with custom-extended versions of your programming languages to let you as the developer actually specify how the program should interact with the limitations of the x86 chip. Those days are gone, and we’re glad to see them go, but those limitations sometimes encouraged worthwhile or beneficial design and implementation decisions. This article is about replicating those, with a focus on the DOS-contemporary Motorola 68000 chips.
- Cursors. Even when pointers are unavailable or inexpensive, pointer-based data structures can still be feasible. The worked example here is linked lists on the 6502.
Modern Systems
A collection of explainers and techniques to ensure that some things that are not quite forgotten are not lost. For a more thorough (and much longer!) account of my various adventures with modern tools and libraries, see the Modern Systems Platform Guide.
- Makefiles for Mortals. Make is actually a useful tool, and most small- or mid-sized projects don’t really need multiple layers of build automation. Getting the most out of Makefiles though does require a little finesse.
- Dynamically Linked Code. “Loading and running” a program has meant a lot of different things over the years, even if you restrict yourself to PCs. I’ve written a brief survey of loading techniques, and then dug deeper into shenanigans you can get up to with DLLs or their equivalents on modern non-Windows systems. When you’re done with shenanigans and just want things to work, though, I’ve also assembled some useful tips for taming dynamic libraries when they misbehave.
- Aspect-Corrected Display Scaling. A lot of the open-source work I’ve done has revolved around getting relatively low-resolution pixel displays to render properly on modern operating systems and displays. A basic part of that is to make sure that the actual “screen” is the correct shape and size, no matter what size the window itself is. Dedicated 2D systems are different enough from one another, and from 3D systems used for 2D rendering, that I’ve needed to accomplish this in many different ways. So far, I’ve done this for the OpenGL 3.2 Core Profile and Cairo under GTK, SDL2, and Direct3D 9. For 3D scenes, I’ve discussed how to get OpenGL to cooperate.
- Custom printf-like Routines. The C standard has a pretty good idea of how it wants people to expose generic logging interfaces that present capabilities like its own standard I/O, but actually implementing it properly is not particularly direct or intuitive. This tutorial covers both
va_argsinterface generally and thevprintffamily of functions that use them, and presents reference code for logging through a much more primitive output interface. It easily generalizes to things like GUI toolkits. - Basics of OpenGL. I created a simple program that draws a textured rectangle and walked through various approaches to drawing it in the OpenGL libraries as it evolved over the decades, with one article covering OpenGL 1.x and another working through the later shader-based APIs. I’ve also covered an improved magnification filter for pixel art, though developers relying on SDL as their hardware abstraction layer will get something equivalent starting in SDL 3.4 (
SDL_SCALEMODE_PIXELART). Still, OpenGL or WebGL developers may find something of use here.