Thursday, March 02, 2006

ASM: Introduction to Video Programming

Because I used to do a lot of graphics programming in inline assembly, I wanted to get back into doing work with video memory directly. Below is a simple program that will simply change the video mode to 320x200 256 colors and set the screen to whatever is in the 3rd palette entry (in my case, it was a baby blue).

0BD0:0100 B81300        MOV     AX,0013
0BD0:0103 CD10          INT     10
0BD0:0105 B800A0        MOV     AX,A000
0BD0:0108 8EC0          MOV     ES,AX
0BD0:010A 31FF          XOR     DI,DI
0BD0:010C B80303        MOV     AX,0303
0BD0:010F B9007D        MOV     CX,7D00
0BD0:0112 F3            REPZ
0BD0:0113 AB            STOSW
0BD0:0114 B410          MOV     AH,10
0BD0:0116 CD16          INT     16
0BD0:0118 B80300        MOV     AX,0003
0BD0:011B CD10          INT     10
0BD0:011D B8004C        MOV     AX,4C00
0BD0:0120 CD21          INT     21

Lets look at the program piece by piece.

MOV     AX,0013
INT     10

The video mode to set gets stored into register AX, and interrupt 10 will call the video interrupt to change it. There is a more thorough list of graphics modes can be found here.

MOV     AX,A000

What I am doing here is setting up ES:DI to point to video memory at A000:0000. I need this set up in order to use the STOSB/STOSW instruction. A000:0000 is different than the video memory at B800:0000, so don’t confuse the 2. The video memory at A000:0000 stores pixel information, 1 byte for each pixel, which relates to a palette entry. So if A000:0001 is equal to 3, this is the 3rd palette entry.

MOV     AX,0303
MOV     CX,7D00

What I have done here is set AX to 0303, which is basically 2 bytes of value 3, and this will get transferred to video memory to set all elements to point to the 3rd palette entry. CX then gets set to 7D00, which is the hex value for the number of pixels, divided by 2. The reason I divide these by 2 is so I can use a word operation instead of a byte operation. So I will copy the entire value of AX to ES:DI the number of times stored in register CX, which is what the REP prefix will do on the STOSW instruction. Note, once saved and unassembled, DEBUG puts REP and STOSW as two separate instructions, however I keyed them into debug as 1 line.

MOV     AH,10
INT     16

This will wait for a key press from the user, to keep the color up on the screen.

MOV     AX,0003
INT     10

This will set the video mode back to mode 3, which is the 80x25 text mode normally used in DOS.

MOV     AX,4C00
INT     21

And this will return up to DOS.

This program works directly with the video memory, it doesn’t rely on interrupts to set the color at a particular pixel, which can be a slow process. Back in the old days of DOS programming, this was a trick that game programmers used in order to keep the latency of screen draws down. There are other techniques that are used, such as double buffering, but I won’t get into those since they are outside of the scope of my interest. In my next article, I will take off this idea, and have each column on the screen show 1 color in the palette, and have the palette displayed across the screen. This will demonstrate how to use the push and pop instructions to allow for controlled inner loops.


Anonymous said...

Great information, Good Job!

Anonymous said...

Could you please put up info regarding bios interrupt routines.
I need to codeup a few interrupt routines similar to those in BIOS.