THE MAD X86 ASM PROGRAM
[ Abstract | Rendering Time | Deep Dive | Repo | Creative Assets ]
MAD magazine No. 258 from October 1985 prominently features The MAD Computer Program, a BASIC program that outputs the MAD logo, Alfred E. Neuman’s face, and his iconic motto, “What, me worry?”. The magazine provides code in BASIC dialects for the Apple II series, the Atari 8-bit family, the Commodore 64/128, and DOS PCs.
This article presents a port of the PC version to x86 assembly language. It compares rendering times. And it explains how both programs work.
The video below depicts DOSBox emulating an original IBM PC (Intel 8088 @ 4.77 MHz). It shows the BASIC program load, list, and run. Over the span of 24.3 seconds, Alfred E. Neuman’s face, the MAD logo, and Alfred E. Neuman’s motto materialize. Then the video moves onto the assembly language program. It takes only 0.6 seconds—a whopping 40.5 times faster than its BASIC counterpart.
The MAD Computer Program renders in CGA’s medium-resolution mode, which displays 320×200 pixels and four colors restricted to two preset color palettes with dark or light intensities. However, the background can be set to any of sixteen different colors.
The program selects the dark green-red-brown palette and a gray background:
20 KEY OFF:SCREEN 1:CLS:COLOR 7,0
The assembly language program calls BIOS routines to do the same:
; Change to CGA's medium-resolution mode (320x200 pixels, 4 colors) mov ax, 0004h int 10h ; Set background color to gray mov ah, 0bh mov bx, 0007h int 10h ; Select green-red-brown palette mov ah, 0bh mov bx, 0100h int 10h
The MAD Computer Program generates Alfred E. Neuman's face and the MAD logo by drawing 522 line segments. It retrieves the endpoint coordinates from DATA statements comprising most of the code:
500 DATA -27,-11,-23,-6,-28,-13,-22,-6,-20,-5,-12,-5,-27,-14,-26,-13 510 DATA -38,-29,-42,-28,-40,-28,-50,-16,-8,13,0,13,-29,4,-29,9 520 DATA -50,-17,-41,-28,-49,-17,-50,-8,-8,12,0,12,-28,5,-28,13 530 DATA -50,-15,-49,-10,40,-26,42,-17,-4,9,-21,14,5,48,2,44 540 DATA -53,-39,-45,-48,-55,-23,-55,-28,-61,-23,-58,-22,-42,-39,-43,-39 ...
The assembly language program stores each line segment byte-packed into double words (y1|x1|y0|x0):
dd 0x64765f7a, 0x66745f7c, 0x5e885e7e, 0x67766677, 0x76687564, ... dd 0x6a5b615a, 0x4d964d8c, 0x54744c74, 0x685a635b, 0x73c66ac8, ... dd 0x704d6f50, 0x80628064, 0x90c18dc1, 0x9170896a, 0x95779170, ... dd 0x62ae61a2, 0x6c79687a, 0x6b77687c, 0x6c7c6b78, 0x6b7a697d, ... dd 0x7a917a90, 0x7d8f7d8f, 0x79907990, 0x768e768e, 0x82687967, ... ...
The MAD Computer Program renders thick segments by drawing parallel lines horizontally separated by a single pixel:
70 LINE (PX,FY)-(LX,LY),2:LINE (PX+1,FY)-(LX+1,LY),2
Since there is no BIOS routine for line drawing, the assembly language program contains an implementation of Bresenham's algorithm. To simplify the implementation, when the endpoint coordinates were byte-packed, they were sorted to guarantee y0 ≤ y1. And rather than drawing two lines, the assembly language program plots a single line consisting of horizontally-adjacent pixel pairs.
There is a BIOS routine to plot a pixel, but it is inefficient. So, the assembly language program writes directly into video RAM, where each byte stores the colors of four consecutive pixels. The program separately handles the case of a pixel pair within the same byte, and a pair split across two bytes.
Annoyingly, CGA stores the even-numbered scanlines and the odd-numbered scanlines in separate memory banks. Although CGA provides a composite output for NTSC CRTs, the memory layout is unrelated to interlaced video. Rather, memory was arranged to accommodate the timing circuitry and the scanline width (details here). When the assembly language program plots pixels, it accounts for the separate banks.
To push performance to the max—at the expense of readability—the assembly language program employs self-modifying code. For example, in the following snippet, the program retrieves an x1 endpoint coordinate from a double word. But instead of storing it into a variable, it injects the value directly into comparison instructions that get executed as the line drawing algorithm runs.
mov ah, [si] ; x1 = *si; mov [.x1_0+2], ah ; modify code: cmp x0, x1 mov [.x1_1+2], ah ; modify code: cmp x0, x1
Upon completion of the drawing, the MAD Computer Program prints Alfred E. Neuman's motto:
90 LOCATE 24,13:PRINT"WHAT, ME WORRY?";
Because the motto contains an odd number of characters, it cannot be centered on the 40-character-wide display. To compensate, the program centers Alfred E. Neuman's face and the MAD logo at pixel column 150, rather than 160:
But based on the location and the width of the motto, the center should be 156. Perhaps the authors incorrectly eyeballed it.
Furthermore, unlike CGA's text modes, the graphics modes do not store character values in video RAM. They just store individual pixels. This means that strings could be drawn anywhere. But, for historical reasons, the LOCATE statement does not do that.
The assembly language program relies on BIOS routines to print the motto. And as if those routines were designed just for the LOCATE statement, they have the same text-positioning limitation.
After printing the motto, the MAD Computer Program waits for a keypress. Then, it switches to 80×25 character, 16-color text mode, where it prints the copyright message:
110 SCREEN 0:WIDTH 80 120 LOCATE 12,23:PRINT"COPYRIGHT 1985 E.C. PUBLICATIONS";
The assembly language program switches to the same text mode with yet another BIOS routine call. But it prints the copyright message by writing directly to video RAM.
In CGA's text modes, even-numbered bytes contain ASCII values, and odd-numbered bytes contain foreground and background color attribute nibbles. The CGA designers should have partitioned the ASCII values and the attributes into separate banks, like what they did for the scanlines, because strings are typically stored as contiguous bytes of ASCII in CPU RAM, string-related instructions and routines are not designed to handle attributes, and the characters in strings tend to be printed all with the same attribute.
Finally, after waiting for a second keypress, the programs terminate, returning the user to the DOS prompt.
This repository contains the sources and compiled binary. Here are direct links to the BASIC and ASM programs, and the COM file.
The assembly language program uses Netwide Assembler (NASM) syntax. And it employs the CPU directive to restrict assembly to the 8086/8088 instruction set:
To assemble the program into a COM file, execute the following command.
nasm mad.asm -f bin -o mad.com ⮺
To slow DOSBox down to the speed of an original IBM PC, in the DOSBox conf file, adjust the performance setting as shown below.
cycles=315 # Intel 8080 @ 4.77 MHz
The MAD Computer Program, the MAD logo, and Alfred E. Neuman’s face and motto are the copyrighted, intellectual property of E.C. Publications, Inc., a subsidiary of DC Entertainment, a subsidiary of Warner Bros. Discovery. The author of this page is not affiliated with or endorsed by them.
© 2023 meatfighter.com