The 8086 is the 16-bit processor Intel made in 1978. Every PC since is its descendant, and it is still taught because each of its instructions does one small, visible thing: copy a number into a register, add two registers, jump to another line. Writing assembly language means writing those instructions yourself, one per line.
In StepVioz your program runs on an 8086 emulator inside the browser. Press Visualize under any example: every instruction is one step, and you see each register, flag, variable and the stack change.
The shape of a program
Almost every program in this course has the same frame:
.MODEL SMALL ; one segment for code, one for data
.STACK 100H ; 256 bytes of stack
.DATA ; variables go here
.CODE ; instructions go here
MAIN PROC
MOV AX, @DATA ; point DS at the data...
MOV DS, AX ; ...so the variables can be used
; your instructions
MOV AH, 4CH ; end the program:
INT 21H ; hand control back to DOS
MAIN ENDP
END MAIN ; the program starts at MAIN
| Line | Meaning |
|---|---|
.MODEL SMALL | the memory model: code in one 64 KB segment, data in another |
.STACK 100H | reserves the stack (100h = 256 bytes) |
.DATA / .CODE | start the data section and the instruction section |
MAIN PROC ... MAIN ENDP | a procedure called MAIN, holding the instructions |
END MAIN | the last line: the program starts at MAIN |
Anything after a ; is a comment. Numbers ending in H are hexadecimal: 4CH is 76.
Printing a character
DOS, the operating system these programs ran under, offers services through INT 21h (interrupt 21 hex). You put the number of the service you want in register AH, then call INT 21H. Service 2 prints the character whose code is in DL:
; Print one character with INT 21h, service 2.
.MODEL SMALL
.STACK 100H
.CODE
MAIN PROC
MOV DL, 'A' ; the character to print
MOV AH, 2 ; service 2: print the character in DL
INT 21H
MOV AH, 4CH ; service 4Ch: end the program
INT 21H
MAIN ENDP
END MAIN'A' is the character's code, 41h (65). The program does not need the data segment, so it skips the two DS lines.
Printing a message
Service 9 prints a whole string. The string lives in the data segment, ends with a $ sign (the $ itself is not printed), and DX must hold its address. LEA DX, MSG loads that address:
; Print a message with INT 21h, service 9.
.MODEL SMALL
.STACK 100H
.DATA
MSG DB 'Hello, 8086!', 0DH, 0AH, '$'
.CODE
MAIN PROC
MOV AX, @DATA ; point DS at the data
MOV DS, AX
LEA DX, MSG ; DX = the address of MSG
MOV AH, 9 ; service 9: print the string at DS:DX up to $
INT 21H
MOV AH, 4CH ; end the program
INT 21H
MAIN ENDP
END MAINThe bytes 0DH, 0AH are a carriage return (back to the start of the line) and a line feed (down one line): together, a new line.
Why MOV AX, @DATA and MOV DS, AX?
The 8086 reaches memory through segments. DS, the data segment register, says where the variables are. When a program starts, DOS leaves DS pointing at its own bookkeeping area, not at your data, so the program must set it. A segment register cannot be loaded with a number directly, so the address of the data, @DATA, goes through AX first. Forget these two lines and the program reads the wrong memory; StepVioz stops it and says so.
Common mistakes
- Forgetting
MOV AX, @DATAandMOV DS, AXin a program with a.DATAsection. - Forgetting the
$at the end of a string printed with AH = 9: DOS keeps printing whatever bytes follow. - Forgetting
MOV AH, 4CHandINT 21Hat the end: the CPU does not stop by itself, it runs on into whatever comes next. - Putting the service number in AL instead of AH.
Quick check
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.