What everybody really needs is a good, thorough introduction to assembler which explains the basics before going deeper into technical info. One good online tutorial of this kind I've found is here:

http://udgftp.cencar.udg.mx/ingles/tutor/Assembler.html

Also check The x86 Assembly Language Webring, which as you might guess from the name is a webring about assembly language for x86 chips, which refers to the Intel x86-series, the 286, 386, 486, etc. Pentiums are also included.

And check http://www.riverland.net.au/~mdunn for a few examples of neat asm tricks, like how to control the speaker, etc. (This is where I learned how to make a TSR.)

I should, however, include some material of my own. So, in my own style of simply jumping into an example and then explaining how everything works, here are some small programs in assembler to do various things.

A program which turns on your mouse cursor

;Turns on mouse cursor
MOV AX,01
INT 33h
MOV AH,4C
INT 21h

The first line of this program is simply a comment. In assembler, a semicolon begins a comment, and the comment then continues through to the rest of that line.

The MOV AX,01 line puts a value of 01 (in other words, simply 1) into AX, which is a CPU register. Registers are small temporary storage areas in your CPU used for data processing.

The line INT 33h calls software interrupt number 33, which is used for mouse functions. (Software interrupts are mini-functions built into your computer.) INT 33 gets all its instructions from AX. Whatever we've specified for AX will tell INT 33 what to do. In this case, we've specified 1, which means we're telling INT 33 to turn on the mouse cursor. That's exactly what it will do now.

The final two lines are simply here for the purpose of program termination. INT 21 gets its instructions from AH, and when we feed 4C to it, that tells it to turn off the program. (This is important. If we omitted these last two lines from this program, the mouse cursor would be turned on, but the program would then stop running and lock up the computer.)

By now, you are no doubt wondering: How do I know that INT 33 controls the mouse and that MOV AX,01 will tell it to turn on the cursor? Sure, it's easy enough if you know that, but where might you find that information?

The answer is very simple: External references. Whole books have been written on INTs and registers and the MOVs that run them. Get a book from your local library that explains it all. Better yet, buy one. If you want to become a serious programmer, you will be referring to it constantly.

If you don't want to buy a book, or are simply too lazy to go to a library, you can also easily find complete INT lists on the Internet. In fact, from right here, you can download a program called HelpPC 2.10, which is a reference program chock-full of useful information for programmers and advanced computer users.

Download it here

You can also get HelpPC from Simtel at the following link:

ftp://ftp.simtel.net/pub/simtelnet/msdos/info/helppc21.zip

Now that you have a program telling you everything you need to know, you may be wondering exactly how to create assembler programs. The small program listed above looks interesting enough, perhaps, but how do you run it? Just type it in at the computer's command line? Answer: No. You must use a compiler. Just like BASIC and C and Java, assembler is still not pure, raw machine code, and so you must use a program to translate it so the computer can run it.

If you use MS-DOS or Windows 95, you already have a program which can compile assembler instructions: Debug. It comes with MS-DOS and Windows 95. At the command prompt, simply type debug and press ENTER. You'll get a hyphen for a prompt. (Debug is remarkably unintuitive, but makes up for this with power.) Now, if you want to create the program above, you might as well name the program before you start. This can be done by typing simply n filename where "filename" is the name you want to give the file. (Use .COM for the extension, since this is a program.) N is Debug's command for specifying the file name. Most of Debug's commands are one character, actually. (I did say it was unintuitive.) Now you can type A and press ENTER. This is Debug's command for "assemble", and you can now begin typing in the program, pressing ENTER at the end of each line, of course. (Ignore the first line when typing it in, since it's just a comment anyway.) Once you're done, make a note of the number at the end of the prompt. That number shows how many bytes you've entered so far. (Minus 100. Notice that it starts at 100, so the actual number of bytes is 100 less.) For this particular program, you will see that it is 9 bytes long. Now, press ENTER to exit assembling and return to the hyphen prompt. One minor quirk of Debug is, you must specify the byte size of the programs you write before you save them. So, type RCX (short for Register CX). This will have Debug show you the current value of register CX (it will be 0), and the prompt will become a colon, indicating it wants you to type a new value for CX. Type 9 and press ENTER (since we're writing 9 bytes). Now, just type w (for "write") to save the program. All done. You can now type q (for "quit") to exit Debug.

The program is now in the current directory. If you want to see your mouse cursor, just run the program (make sure you have a mouse driver loaded first). You should now see it and be able to move it with the mouse.

By the way, notice the INT numbers above have an H after them. This is because some assembler compilers assume if you just use plain numbers that they should be converted into their hexadecimal values. Debug doesn't but A86, a very popular compiler, does. Basically, it would use INT 21 where it's supposed to use 33 (33 decimal = 21 hex) and 15 where it's suppoed to use 21 (21 decimal = 15 hex). Putting the H after clears up any problems that might come up with this.

Oh, and if you want to turn the cursor back off, here's a program which does just that:

MOV AX,02
INT 33h
MOV AH,4C
INT 21h

As you can see, this program is almost identical. The only difference is, a value of 2 in AX tells INT 33 to turn the cursor off.

Pause the computer until a mouse button is pressed

MOV AX,5     ;5 in AX tells INT 33 to get mouse button info
INT 33h      ;get mouse button info
CMP AX,1b    ;this compares AX (button status) with 1
JL  0100h    ;if no button is pressed, back to start

;AX will be zero while no button is pressed. JL means, if the first
;operand is less than the second, make the jump!

mov ah,004C  ;terminate program
int 21h

The operation of this program should be fairly simple and obvious.

"Hello, world."

This next program prints out the canonical program test message: "Hello, world." Just about everybody's first program in BASIC or C is a program that prints out this message. Here's one in Assembler that does it

MOV AX,SEG MESSAGE
MOV DS,AX               
MOV DX,OFFSET MESSAGE

;These three lines make DS:DX form a pointer to the segment:offset of
;MESSAGE. Note that AX is used as a go-between for the segment,
;because some assembler compilers don't allow you to MOV immediate
;values into segment registers (like DS) directly. Some do, some don't.
;Just to avoid problems, instead of MOV DS,SEG MESSAGE, we do
;that to AX and then MOV DS,AX.

mov ah,0009             ;9 in AH makes INT 21 print the string
int 21h                 ;referenced in DS:DX.
mov ah,004C             ;terminate program
int 21h

MESSAGE: DB 'Hello, world.$'

This program should also be fairly obvious. It introduces some new concepts, but just study it and I'm sure you'll figure out what everything does.

Create a textual mouse "button"

And now, yet another mouse program. This whole program is completely self-explanatory. It's bigger than the ones above, but it's well-commented.

;Gives you an on-screen button to click on with the mouse, and
;proceeds only when you do!
mov ah,06h ;this calls SCROLL SCREEN UP
mov al,00h ;AL specifies how many lines... 0 just clears the screen
mov ch,00h
mov cl,00h
mov dh,24h
mov dl,80h
int 10h

;The above lines just clear the screen.

mov ah,02h ;Set cursor position
mov dh,0Bh ;row
mov dl,22h ;column
int 10h    ;Actually does it. :)
MOV AX,SEG MESSAGE
MOV DS,AX               
MOV DX,OFFSET MESSAGE

mov ah,0009             ;9 in AH makes INT 21 print the string
int 21h                 ;referenced in DS:DX.

;So, we have printed BUTTON right where we want it!!!

mov ax,0001
int 33h

;Now, that's got the mouse on.

MOUSLOOP:

MOV AX,5     ;5 in AX tells INT 33 to get mouse button press into
INT 33h      ;get mouse button info
CMP AX,1b    ;this compares AX (button status) with 1
JNE MOUSLOOP ;unless LEFT button ONLY is pressed, go back to MOUSLOOP

;(Only the left button will work for this... Not the right.)

MOV AX,3
INT 33h      ;Now we're getting the POSITION info through INT 33,3!

;CX now is mouse horizontal position. 0 - 639
;DX now is mouse vertical position. 0 - 199

CMP CX,270
JL MOUSLOOP ;If CX is less than 270 (left edge of button), go back
CMP CX,315
JG MOUSLOOP ;If CX if more than 400 (right edge), go back
CMP DX,85
JL MOUSLOOP ;If DX is less than 85 (top), go back
CMP DX,95
JG MOUSLOOP ;If DX is more than 110 (bottom), go back

;The numbers above for the button dimensions are approximations, but
;should be good enough.

mov ax,0002
int 33h

;This just hides the cursor. Otherwise it would stay on when the program
;ended! :)

mov ah,004C             ;terminate program
int 21h

MESSAGE: DB 'BUTTON$'

Check for the presence of a mouse driver

Often, a program wants to simply check if a mouse driver has been installed or not. (Usually on startup of a program which requires a mouse, so the program can abort with a "No mouse driver" error if needed.) Here's a program which displays an error message if there is NO mouse driver, and exits silently if a driver was detected.

MOV AX,0000
INT 33h
CMP AX,0000
JNE Ender
;Code here to perform if mouse driver is not installed.
MOV AH,09
MOV DS,SEG Message
MOV DX,OFFSET Message
INT 21h

Ender:

mov ah,004C  ;terminate program
int 21h

Message DB 'ERROR: Mouse driver was not detected.$'

Return errorlevel based on presence of mouse driver

A simple addition to the previous program which returns an errorlevel based on the presence of a mouse driver: Returns 0 if the driver was detected, or 1 if no driver was detected. (In DOS, an errorlevel of 0 is the standard code to signify "no error.")

;Checks for mouse driver, returns errorlevel of 0 if no error, returns
;errorlevel of 1 if error (i.e. mouse driver not installed)
MOV AX,0000
INT 33h
CMP AX,0000
JNE Itsok
;Code here to perform if mouse driver is not installed.
MOV AL,01 ;Return errorlevel of 1 (indicating an error)
JMP Ender

Itsok:
MOV AL,00 ;Return errorlevel of 0 (no problem)

Ender:

MOV AH,4Ch  ;terminate program
INT 21h

Reset dates on files

That was fun, but now let's move away from the mouse. Here's a utility to reset dates on files to January 1, 1980 at 12:00:00 AM (which is the earliest date DOS supports on files). Very handy for when you want to forget about when something happened.

;The following 5 lines just clear the carry flag (CF), which is important,
;because clearing the carry flag makes INT 21,3D return the file handle
;instead of an error code.
PUSHF ;transfer 16-bit flag register onto stack
POP AX ;AX now contains the flag register contents
AND AX,0FFFEh ;sets rightmost bit (carry flag) to 0
PUSH AX
POPF

MOV AH,3Dh ;open file using handle
MOV AL,1 ;write only
MOV DS,SEG filename
MOV DX,OFFSET filename
INT 21h

;AX should now contain the file handle.

MOV BX,AX ;transfer file handle to BX where it belongs
MOV AH,57h ;set file date/time using handle
MOV AL,1 ;set (not read) date and time
MOV CX,0 ;12:00:00 AM
MOV DX,21h ;January 1, 1980 (0000000000100001)
INT 21h

MOV AH,3Eh ;close file using handle
;BX already contains the appropriate file handle from the previous operation,
;so we don't need to re-set it.
INT 21h

mov ah,004C  ;terminate program
int 21h

;Edit the line below as appropriate to reflect the actual filename of the
;file whose date you want to reset.
filename DB 'newfile.txt', 00

A TSR shell

Here's a TSR shell. It provides the framework for what you need to make a program that stays resident in memory (now you just need to put the function that the memory-resident program should perform at the indicated point):

;HOW TO MAKE A TSR:
;STEP 1. Get the interrupt vector of INT 8.
CLI ;turn off hardware interrupts
MOV AL,8h ;specifies INT 8
MOV AH,35h ;get interrupt vector
INT 21h
;STEP 2. Make INT C8 behave like INT 8.
;(INT C8 isn't used by anything anyway.)
MOV DX,BX
PUSH ES
POP DS
;the above three lines set DS:DX to whatever ES:BX was
MOV AL,0C8h
MOV AH,25h ;set INT C8's vector (makes INT C8 behave like INT 8)
INT 21h
;STEP 3. Set INT 8's vector to your own interrupt function.
MOV DX,OFFSET TSRINT
PUSH CS ;push the Code Segment...
POP DS ;...to make DS equal this routine's segment
MOV AL,8
MOV AH,25h ;set INT 8 to behave like your new interrupt function
INT 21h
;STEP 4. Do INT 21,31 and you're done.
MOV AL,0 ;exit code (for batch files)
MOV DX,0FFh ;how much memory is reserved for this TSR
MOV AH,31h ;make it into a TSR now
INT 21h

TSRINT:
;THIS IS THE ACTUAL CODE OF THE INTERRUPT ITSELF:
CLI ;disable interrupts
PUSHA ;save current registers status for later

;YOUR INTERRUPT ROUTINE HERE! This is where the code of the actual interrupt
;function (the process which the TSR should keep repeating while it's in
;memory) should go.
;A reminder: PUSHA is used above to save the registers so they can be easily
;restored to their former states with POPA later. However, PUSHA and POPA
;only affect (E)AX, (E)CX, (E)DX, (E)BX, (E)SP, (E)BP, (E)SI, and (E)DI. They
;do NOT affect any of the segment registers (CS, DS, SS, or ES), meaning that
;if your routine uses these registers, you will also need to save them by
;PUSHing them before this interrupt routine, and POPing them after it's over.

POPA ;restore old register status (so everything's the same as before)
INT 0C8h
;do the old INT 8 as well, otherwise what should be INT 8 never gets done

PUSH AX
MOV AL,20h
OUT 20h,AL ;this sends an End-Of-Interrupt signal to the 8259 int controller
POP AX

STI ;re-enable interrupts (opposite of CLI)
IRET ;interrupt return (signifies that the interrupt is over)

Print the date of the BIOS

A standard PC BIOS stores its release date as an 8-byte string in memory location FFFF:5. This program prints that string.

;Print from ROM, starting at FFFF:5 for 8 characters
;(This shows the date of the ROM BIOS)
MOV DS,0FFFFh
MOV SI,5
MOV CX,8

mainloop:
MOV DL,[SI] ;DL = character to output
MOV AH,2
INT 21h ;print the character
INC SI ;move SI to the next byte
LOOPNZ mainloop ;this loops 8 times, because CX was set to 8

mov ah,004C  ;terminate program
int 21h

Draw a pixel in a graphics mode

By default, DOS prompts are text-only, meaning you can't draw graphics on the screen with them. However, you can change your graphics mode with INT 10,0. This program starts off by switching to the famous mode 13 (320x200 256-color VGA, a very popular video mode for amateur DOS games) and then draws a single pixel to demonstrate the graphical capabilities of this mode.

;Draws a single yellow pixel in the upper-left.
;Writes directly to video memory which begins at A000:0

mov ah,00h
mov al,13h
int 10h

;The above three lines just switch to 320x200 256-color VGA.

mov ds,40960
;a000h = 40960 decimal
mov ax, 44h
;44h is yellow! ;)
mov bx,0000
mov [bx],ax

;This defaults to DS:[whatever], and since whatever here is bx, it moves
;AX into DS:BX!!!


mov ah,004C  ;terminate program
int 21h

Draw a line in a graphics mode

;By extension, draws a yellow line in the upper-left.
;A good example of how to efficiently use INC, CMP,
;and a conditional jump for repetitive tasks.

mov ah,00h
mov al,13h
int 10h

;The above three lines just switch to 320x200 256-color VGA.

mov ds,40960
;a000h = 40960 decimal
mov ax, 44h
;44h is yellow! ;)
mov bx,0000
START:
mov [bx],ax
inc bx
cmp bx,20
JL START

;This waits until BX reaches 20, then exits!

mov ah,004C  ;terminate program
int 21h

Draw a single pixel in each color available in video mode 13

;prints all possible 256 colors in a row, in order from 1 to FF,
;along the top of the screen.

mov ah,00h
mov al,13h
int 10h

;The above three lines just switch to 320x200 256-color VGA.

mov ds,40960
;a000h = 40960 decimal
mov bx,0000

mov ax, 01h
MAINLOOP:
mov [bx],ax
inc bx
inc ax
cmp ax,0FFh
JNG MAINLOOP

mov ah,004C  ;terminate program
int 21h

Turn on all keyboard "lock"s

This program turns on Caps Lock, Num Lock, and Scroll Lock.

;Move F0h to 40:17

MOV DS,40h
MOV BX,17h
MOV AX,0F0h
MOV [BX], AX

mov ah,004C  ;terminate program
int 21h

Turn off all keyboard "lock"s

;Move 80h to 40:17

MOV DS,40h
MOV BX,17h
MOV AX,80h
MOV [BX], AX

mov ah,004C  ;terminate program
int 21h

Turn the first pilot in a Gunship 2000 roster into a 2nd Lieutenant

Gunship 2000's excellent add-on, Islands And Ice, only lets you use its mission editor after you have attained a rank of at least 2nd Lieutenant (2LT). This is, frankly, outrageous, since you should be able to make your own missions at any time. This program is a simple way of dealing with this problem. It edits Gunship 2000's roster file, ROSTER.DAT, so that the first pilot in the roster is made a 2nd Lieutenant. If you want to change a pilot other than the first one in the roster, you can just edit the number of bytes which the program moves forward in the file. Currently it is set to 54h.

;Set byte 54h of file to 5. This will make you a 2nd Lieutenant (2LT),
;which in turn will let you use the mission builder.

MOV AH,3Dh ;open file using handle
MOV AL,01 ;write only
MOV DS,SEG FILENAME
MOV DX,OFFSET FILENAME
INT 21h

;AX is now the file handle

MOV BX,AX ;moves AX (the file handle) into BX
MOV AH,42h ;move file pointer
MOV AL,0
MOV CX,0 ;high order word of number of bytes to move
MOV DX,54h ;low order word of number of bytes to move
;Move 54h bytes, since that's where the byte we want is
INT 21h

;BX is still the file handle
MOV AH,40h ;write to file using handle
MOV CX,1 ;number of bytes to write
MOV DS,SEG BUFFER
MOV DX,OFFSET BUFFER
INT 21h

mov ah,004C  ;terminate program
int 21h

FILENAME db 'ROSTER.DAT', 00
;The 00 on the end is to terminate the filename with a 00 character,
;making it an ASCIIZ string.

BUFFER db 5
;BUFFER is what will actually get written to the file.

Well, that's all for now. If you have any advice or comments, please e-mail me. Thanks.

Back to the main page


This page hosted by Get your own Free Homepage