Creating Video Games

Some background:

There are lots of video games out there written for 16 bit, and with a little work, it is still possible to create one.  Unfortunately, the documentation is harder to come by.  I no longer have my texts detailing the various graphics modes and how they work.  But I have lots of examples and found some additional resources online. You may have to do some leg-work to make your graphics happen.  You can search links for programming various video cards, which are listed below.

Video card standards

CGA (Color Graphics Adapter) was the first standard that could be used for graphics. It was introduced by IBM in 1981, but such cards were very expensive and 320x200 with 4 colors or 640x200 with 2 colors was incommensurate to professional use. After EGA cards were introduced, the CGA cards became affordable and were considered as cheap solution.

HGC (Hercules Graphics Card) was a monochrome graphics controller developed by Hercules Computer Technology, Inc. in 1982. It supported a high-resolution text mode with a clearer text display than the CGA standard ever could offer, and a single graphics mode in 720x348. The Hercules cards were widely supported and usually connected to a monochrome monitor with a green, yellow or white display.

EGA (Enhanced Graphics Adapter) was developed by IBM as a successor to CGA in 1984. Such cards were able to display 16 colors at resolutions up to 640x350, but you needed a special EGA monitor to do this.

VGA (Video Graphics Array) is a video card standard introduced in 1987. It is still supported today (December 2008). It's advantage was that you was able to use a wide range of display modes, even though they were limited to 400 lines at 70 Hz or 480 lines at 60 Hz. The most common modes were 320x200 at 256 colors and 640x480 at 16 colors.

VBE (VESA BIOS Extension) originally was an enhancement to VGA and supported more powerful video modes. In 1989, it was first specified as SVGA (Super Video Graphics Array) by the Video Electronics Standards Association (VESA) and later enhanced up to a resolution of 1600x1200. As not all video cards supported such functionalities, there were additional programs like UniVBE (later Scitech Display Doctor) to provide them by software.

As IBM had a quasi-monopoly in PC hardware in the 80s, the video drivers for CGA, EGA and VGA have been directly integrated into the BIOS. That was not unimportant, because DOS didn't have a graphical subsystem like GDI, DirectX or the X Window system. Since every software had to use own drivers to use hardware, developers mostly restricted themself to VGA. After 1990, IBM lost his market power. So even today, the VGA driver is the best one, if you didn't have installed the right video driver, yet.  From this link:

1. Change to a VGA resolution.

With BIOS interrupt 13 AH = 00 we're able to change the current screen resolution (See below).

Example: Change to medium resolution:

To go into graphics mode 13h and plot a pixel

1.  Mov ax,13h;MCGA 320x200 256 color graphics mode

2.  Int 10h

3.  mov ax, row

4.  mov bx, column

5.  mov cx,320

6.  mul cx

7.  add ax,bx

8.  xchg si,ax

9.  mov bx, 0a000h;location of video mem for this mode

10. mov es, bx; … note es must be pointing at video mem:

11. mov word [es:si], 9 ; display bright-blue pixel


Al (hex)

video mode


text 40 x 25 16 grey
text 40 x 25 16 color
text 80 x 25 16 grey
text 80 x 25 16 color
graph (CGA) 320 x 200 color
graph (CGA) 320 x 200 black / white
graph (CGA) 640 x 200 black / white
text 80 x 25 black / white (MDA, Hercules)
graph (EGA,VGA) 640x350 grey
graph (EGA,VGA) 640x350 16 colors
graph (VGA) 2 colors
graph (VGA) 16 colors

In the next paragraphs we'll discuss meanly the standard VGA resolution (12h) These days most VGA-boards has "Super VGA" resolutions, in the next table you'll find the information to change to a "VESA Super VGA"

INT 10h

AX = 4F02h

BX = mode



video mode


graph 640x400 256 colors
graph 640x480 256 colors
graph 800x600 16 colors
graph 800x600 256 colors
graph 1024x768 16 colors
graph 1024x768 256 colors
graph 1280x1024 16 colors
graph 1280x1024 256 colors
text 80x60
text 132x25
text 132x43
text 132x50
text 132x60

When your VGA BIOS support this function AH will become 00h, otherwise AH will return 01h. The issues in the next paragraph can also be use in the VESA resolution 800 x 600 16 colors.

2. Write to the video memory

The standard IBM VGA card has 16 color therefore every pixel needs 4 bits (2^4 = 16) The VGA graphical card uses bitplanes, every main color has his own memory area in the video memory. Because the memory address is equal for every main color (A000:0000h memory mapped) we have to program the sequencer to select the right memory bank.

register selection with port 03C4h.




Clocking mode
Map Mask
Character Map Select
Memory mode

With the Map Mask register we can select to which color plane we write.  (translation: blue, green, red, intensity)

Description: Description: [gfx vga_fig1.jpg]

When we set bit 0 we'll write to the blue bitplane, if we set bit 0 and 1 (3) we'll write to the to blue bitplane. The next example will elucidate the above theory.

                .MODEL SMALL
                mov ax,012h    ;VGA mode
                int 10h        ;640 x 480 16 colors.
                mov ax,0A000h
                mov es,ax      ;ES points to the video memory.
                mov dx,03C4h   ;dx = indexregister
                mov ax,0F02h   ;INDEX = MASK MAP,
                out dx,ax      ;write all the bitplanes.
                mov di,0       ;DI pointer in the video memory.
                mov cx,38400   ;(640 * 480)/8 = 38400
                mov ax,0FFh    ;write to every pixel.
                rep stosb      ;fill the screen
                mov ah,4ch     ;go back
                int 21h        ;         to DOS.
               END start

With mov ax,0F02h, out dx,ax we select all the bitplanes this results in the color white. If we change mov ax,0F02h to mov ax,0102h we'll get a blue screen ;-).

3. Video Palette

Another advantange of VGA is the ability to modify the colors, so it's possible to give pictures a more "real" look.
There're two way the modify the video palette program direct to the video hardware or use the video software interrupt (INT 10h). Below you'll find howto change the palette by INT 10h.

With INT 10h AX = 1010h we can change the palette of one color, BX contains the color register, CH the green value, CL the blue value and DH the red value. There is a difference between "color register" and "color number" we can solve this by first request the "color register" of the "color number". We can do this with INT 10 AX = 1007h, BL contains the color number the color register will be returned in BH. The next example will proof that practice is less complicated that the theory.

;Modify the palette of one color.
;BX = color number
;ch = green
;cl = blue
;dh = red  
pal         PROC
            push ax
            mov bh,0
            mov ax,1007h
            int 10h
            mov bl,bh
            mov bh,0
            mov ax,1010h
            int 10h
            pop ax
pal         ENDP

4. Reading the Video memory

Reading the Video memory is more or less the same as writing to it. We have to change the graphical control to read mode. This is possible with port address 03CEh and 03CFh.
The next table gives you a overview of the possible functions.

Mode adjustment by port 03CEh.




Enable Set/Reset
Data Rotate/Function Select
Read Map Select
Graphics mode
Color don't care
Bit Mask

When we set port 03CEh to 3 we set the VGA card in read mode with port 03CFh we can specify the color bitplane to read. In the next table contains the colors with equivalent values.

bitplane selection by port 03CFh



The next procedure will demonstrate the above theory. It read one byte in the 4 color bitplanes (BGRI), with SI we specify the byte address.

               PUBLIC readbyte
;Read one byte in the video memory
;call    : SI byte address
;answer  : al,ah,bl,bh -> bl,gr,rood,inten
readbyte        PROC NEAR
               push cx
               push dx
               push si
               push es
               mov ax,0A000h
               mov es,ax
               mov dx,03ceh           
               mov ax,0005h
               out dx,ax
               mov ax,0304h            ;AH = bitplane, AL = read modus
rb01:           out dx,ax             ;go to read mode 
               mov bh,es:[si]         ;read the blue byte
               dec ah
               out dx,ax              ;AH = green
               mov bl,es:[si]         ;read the green byte
               dec ah
               out dx,ax              ;AH = red
               mov ch,es:[si]         ;read the red byte
               dec ah        
               out dx,ax              ;AH = intensity
               mov cl,es:[si]         ;read the intensity byte
                mov ax,cx
               pop es
               pop si
               pop dx
               pop cx
readbyte    ENDP

5. Different write modes

There're 4 different write modes; replace, AND, OR and XOR, we change the write mode by the "Data Rotate/Function Select" register (see table in paragraph 2).By putting 3 in the selection register 03CEh we select the "Data Rotate/Function Select".

Like the name suggest we also have the ability the rotate the date, this isn't often used since it's faster to rotate the date with the normal processor.

With the dataregister at port address 03CFh we can specify how to the data is written to the screen.

write mode selection by port 03CFh

bit 4 bit3


0 0
0 1
1 0
1 1



mov ax,1803h
mov dx,03CEh
out dx,ax

Will set the VGA card write mode to XOR.

6. Drawing a line

Drawing a line in assembly isn't that easy... and it is very important not to use to complicated functions (cos, sin ...) since this is too difficult to program and (more important) will slow the function.
The most widely used function to draw a line is the so called Bresenham algoritme which is published in IBM System Journal in 1965.

The equation of a line : y = (dy/dx).x

Description: Description: [gfx vga_fig2.jpg]

When the line is closer to point A, we have to draw point A. When the line is closer to point B we need to draw point B.

a = (yi+1) - (dy/dx).xi

b = (dy/dx).xi - yi

(b-a) = 2.(dy/dx).xi - 2.yi - 1

(b-a).dx = 2.(dy.xi - yi.dx) - dx

suppose di = (b-a).dx

di = 2.(dy.xi - yi.dx) - dx

We need to calculate di with the information of the last drawn point:

(di - di-1) =  2.(dy.xi - yi.dx) - dx - 2.(dy.xi-1 - yi-1.dx) + dx

(di - di-1) =  2.(dy.(xi - xi-1) - dx(yi - yi-1))

For the step in the x direction (xi - xi-1) we choose 1.

(di - di-1) =  2.(dy - dx(yi - yi-1))

The value of (yi - yi-1) depends on where we have to draw the point, (yi - yi-1) is 1 when we need to draw point A (yi-1 +1) and will be 0 if we need to draw point B (yi = yi-1).

When we have to draw point A : (di - di-1) = 2.(dy - dx)
When we have to draw point B : (di - di-1) = 2.dy

Excerpted from link above:

The cleanest way to set up your video mode is to go through the video BIOS. It can be performed through the regular Int 0x10 interface, or through the (optional) Protected mode interface offered by VBE3. As you can guess, Int 0x10 requires a 16-bit environment, so you can only use it in Real Mode or Virtual 8086 Mode

Practically, the options are (in order of difficulty):

*  You set up the mode you want at early stage (in the bootloader) before entering protected mode.

*  You let GRUB do the switch for you. (Currently only works with patched GRUB, or GRUB 2. You may download the patches directly from here.)

*  You switch back to Real Mode or Unreal Mode for setting the proper video mode

*  You write a VGA driver that can do low-resolution modes on practically all hardware

*  You use the PMID from VBE3, if present

*  You set up a V8086 monitor that will execute the mode-switching code

*  You run some software code translation tool to produce pmode code out of bios rmode code. (SANiK

 is on the catch


*  You write a driver for your specific graphics card

Locating Video Memory

For standard VGA video modes the video memory will either be at address 0xA0000 or 0xB8000. To find out which one look at the following table (quoting "text" means 0xB8000, CGA graphics modes are also at 0xB8000, and VGA/EGA is at 0xA0000. Note that most EGA modes (and high res VGA modes) use several bit planes so you won't be able to use all the colors by simply writing to video memory.


text 40*25 16 color (mono)


text 40*25 16 color


text 80*25 16 color (mono)


text 80*25 16 color


CGA 320*200 4 color


CGA 320*200 4 color (m)


CGA 640*200 2 color


MDA monochrome text 80*25












EGA 320*200 16 color


EGA 640*200 16 color


EGA 640*350 mono


EGA 640*350 16 color


VGA 640*480 mono


VGA 640*480 16 color


VGA 320*200 256 color

For VESA modes, the framebuffer address is stored in the mode info block. This is the physical address of the linear framebuffer (it's not a 16-bit far pointer but a 32-bit linear pointer) : if you use paging, you have to map it somewhere to use it.

Plotting Pixels


Let's say you want to plot a pixel in red in the middle of your screen. The first thing you have to know is where the middle of the screen is. In 320x200x8 (mode 13), this will be at 100x320+160 = 32160. In general, your screen can be described by:


how many pixels you have on a horizontal line


how many horizontal lines of pixels are present


how many bytes of VRAM you should skip to go one pixel down


how many bits of color you have


how many bytes of VRAM you should skip to go one pixel right.

"pitch" and "width" may seem redundant at first sight but they aren't. It's not rare once you go to higher (and exotic) resolutions to have e.g. 8K bytes per line while your screen is actually 1500 pixels wide (32-bits per pixel). The good news is that it allows smooth horizontal scrolling (which is mainly useful for 2D games :P )

Pitch and pixel width are usually announced by VESA mode info.

Using medium and high resolution graphics we can create simple video games in Intel 86 assembly language.  Since the OS migration to Windows 7, games developed in 16-bit no longer run.  However, we can use various mechanisms to run these programs.  Safemode and Virtual PC might be other ways to do this.

DOSBOX is an 8086 emulator which will let you run 16-bit graphics programs.  Among other things, you can map to a folder to access your exe programs and access full screen graphics.  See help and intro display.

 As an aside, among other things, in the old DOS world, only 6 char filenames, no blanks, with 3-char extensions were allowed.  So cart.asm is okay, but cartesian.asm is not okay.

The examples below could be combined with mouse function int 33h although I haven’t done it except for a version of the high res box below.

Alien code

Here is alien: A little alien guy that moves slowly across the screen.  This might be the start of a game where you shoot at the alien head(s)


Here is snake, a thingy that creeps along and turns a corner.





Here is moveball: spacebar moves ball horizontally across screen.  This and next example might be the basis for Pong game.

Medium resolution ball


Similarly, this ball “bounces” up and down.

(To make pong, ball needs to move horizontally & vertically at the same time.)



This program prints letters/colors

And this changes background:

This program draws coordinate axes.  It might be the basis for a simple graphing program.

Cartesian coordinates

Here is boatgame… Boat and sub move back and forth at different speeds.  Note torpedo has been fired.


This uses high res graphics to draw a rectangle… does not properly terminate in dosbox.


Other links

Medium resolution cellular automata