ASSEMBLY LANGUAGE PROGRAMMING: A LAB MANUAL
Intel 8086: A brief excursion
Using the Assembler
A sample program
Suggested list of experiments
Note to the T.A / Instructor
ASSEMBLY LANGUAGE PROGRAMMING: AN INTRODUCTION
Fetch/Decode/Execute cycle is like a program:
Fetch instruction from primary memory
Increment Program Counter
Fetch operands from memory (if required)
Write results to memory (if required)
How is this "program" written?
eg. ADD Instruction
1. Fetch operand1, store in register X
2. Fetch operand2, store in register Y
3. Tell ALU to add X and Y
4. Put result in ACC
MICROCODE (see fig. below)
Lowest level of software
Flexible: can be updated by designers
Controls the digital logic of the CPU
Implements the machine code instructions
Lowest level of software meets highest level of hardware
IS MICROCODE ESSENTIAL?
Don't have to use microcode at all .
Possible for Machine Code instructions to control logic directly (via Control
Bug fixes are simpler than changing logic
Complex instructions are best implemented as microcode
Instruction execution less efficient than "hard-wired" approach
Each type of CPU has it s own Instruction Set
The set of instructions that can be decoded and executed
Each instruction has a number
Usually written as a "mnemonic"
8086 instruction set (79 basic instructions)
AAA AAD AAM AAS
ADC ADD AND CALL
CBW CLC CLD CLI
CMC CMP CMPS CMPXCHG
CWD DAA DAS DEC
DIV ESC HLT IDIV
IMUL IN INC INT
INTO IRET/IRETD Jxx JCXZ/JECXZ
JMP LAHF LDS LEA
LES LOCK LODS LOOP
MOV MOVS LOOPE/LOOPZ LOOPNZ/LOOPNE
MUL NEG NOP NOT
OR OUT POP POPF/POPFD
PUSH RCL RCR PUSHF/PUSHFD
REP REPE/REPZ RET/RETF REPNE/REPNZ
ROL ROR SAHF SAL/SHL
SAR SBB SCAS SHL
SHR STC STD STI
STOS SUB TEST WAIT/FWAIT
XCHG XLAT/XLATB XOR
TYPES OF INSTRUCTION
Instructions vary from one CPU to another
General groupings possible...
* Add, subtract, AND, OR, shifts
* Performed by ALU
* Load, Store (to/from registers/memory)
Transfer of Control
* Jump, Branch, procedure call
* Set condition flags
* In, Out
* Only on some CPU's
* Halt, NOP
Instruction defined by Opcode and Operands
Decoded by examining bit patterns
If operands used, must specify addresses
Two-address instruction: Opcode Address1 Address2
Instruction Length may be shorter than/ same as / longer than a machine
Operands may be
o implicit (eg. stored in accumulator or on stack)
o stored in
Instruction may need to specify addresses of operand(s) and where to put result
Several ways to interpret address part of instruction (call it addr)
addr is address field of instruction
addr is operand
addr is number of CPU register
operand := [ addr ]
addr is address in primary memory
operand := [ addr ]
addr is register number (or memory address)
operand_address := [ addr ]
operand [ operand_address ]
addr is base address
index is a register
operand := [ addr + [index] ]
Auto-indexing modes allow automatic increment (or decrement) of value in index
8086 ARCHITECTURE :Hardware Overview
PROGRAMMER'S VIEW - REGISTERS
In Intel Processors there are several registers, the registers are special memory locations
that are built right into the chip. These registers are used to mess with data in a program.
All registers can and always work with numbers. The range of numbers that can be
loaded into a register is -65535 to +65535, I think, in hex the range is -FFFF to +FFFF
and finally in binary the range is -11111111 to +11111111. In the Intel processor there
are 4 general use registers:
AX - Called the Accumulator, used in math operations.
BX - Called the Base Register?, not used very often.
CX - Called the Count Register, used as a counter in loops.
DX - Called the Data Register, it just holds data.
All these registers can be split into 2 registers that hold a lower range of numbers. The
range for the split registers is: up to 255 decimal, FF in hex, and 1111 binary. Their
names are derived from the register they were split from:
AX: Contains AH and AL.
BX: Contains BH and BL.
CX: Contains CH and CL.
DX: Contains DH and DL.
When a split register is changed, the large register is changed as well. Example below:
Each split register is in fact PART of the original register it came from. So, if AX is
FF56 in hex. Then AL will be FF and AH will be 56. If you change a split register, you
also change that part of the large register.
The Special Registers
There are also 6 other registers in the Intel Processor. These have special uses too.
However, modifying these registers without knowing what you are doing can crash your
program, or your computer. They are called the Segment Registers:
CS - Code Segment, points to the segment of the currently running program code.
ES - Extra Segment, you can use this one!
DS - Data Segment, points to the segment of data to be used with certain operations.
SS - Stack Segment, points to the stack of the running program code.
For the other two they are NOT Segment Registers and are the most dangerous to mess
BP - Base Pointer, points to the base of the stack.
SP - Stack Pointer, points to the top of the stack.
When a register points to something, that means if read the register will contain the
memory address of what it points to. Also these registers have the same range as the
regular registers, but CANNOT BE SPLIT UP.
The FLAGS are a set of indicators that can have a TRUE (binary 1) or FALSE (binary 0)
value in them. They are modified through the use of set (make 1) and clear (make 0)
operations. They are also modified by any compare operation done. They are used as
error indicators too. They are:
Overflow Flag - Indicates that a number has gone too high to handle.
Carry Flag - Used as an error indicator, or holds the carry from an + or - operation.
Interrupt Flag - Indicates whether or not interrupts are honored or not.
Learn about interrupts later.
Parity Flag - Not used very often, it used to be used to indicate errors but nowadays...
Direction Flag - Used to determine which way text operations work.
Trap Flag - Of no use to us.
Sign Flag - Indicates an above or below after the comarison of numbers.
Zero Flag - Indicates an equal result after a compare operation.
Auxiliary Flag - Of little use to us.
Those are all the flags, as you can see some are leftover from the early days of Intel
Processors and aren't used any more by programmers. These flags are a necessity for a
certain operation I'm not going to tell you about yet. However, flags are very important,
don't ever forget them!
The stack is just a bunch of data that gets stacked on top of each other growing downward
in memory. When a register or all of the flags gets pushed onto the stack, the stack grows
down. When a value is popped off the stack the value popped is the last one that got
pushed on. LIFO: Last In First Out, remember that because that is how the stack works.
They Interrupt the CPU. Interrupts are just what the name suggests, they interrupt the
processor (CPU from now on) and make it do something and then return to what it was
doing before the interrupt. There are several kinds of interrupts, they are:
Hardware - Internal CPU interrupts, we can't use these.
Software - One of the most important things to use.
Each interrupt has a unique number, and each interrupt number has many function
numbers that determine the interrupt function to run. Next section we start coding!
To use an interrupt function you need a function number in the AH split register. And
then you call the interrupt number that contains the function. Here is an example:
mov ah,4ch ; MOVes 4C in hex to AH.
int 21h ; calles the DOS System interrupt number.
Function 4C of int 21h is the end program function, this function is why programs
crashed if you ran assembled code from previous sections. Some functions require
parameters to be passed to them. Parameters are required to be passed in registers.
Registers used for parameters differ from function to function. Here is an example:
mov ah,2 ;MOVes 2 to AH. 2 is the write letter to screen
mov dl,'H' ; DL is where the letter goes. Letters are specified in
int 21h ; 21h is the DOS service interrupt number.
int 21h ; These last two line are to make it work if you
Some functions return one or several values in registers, such as one letter input functions
and so on.
Address bus: 20 bits... 1,048,576 addresses
But internal registers only 16 bits: can't hold a full address
Segment Registers define four 64k "windows" on the address space
8086 addresses are specified as xxxx:yyyy
o where xxxx is value in segment register
o yyyy is offset
Addresses are specified as relative to start of segment
eg. Instruction Pointer relative to Code Segment
Address of next instruction (hexadecimal) is:
IP yyyy +
Addr aaa aa
aaaaa is "effective address" (20 bits)
Put another way:
effective address = 16 * [ segment-reg ] + offset
(Referred to as segment/offset addressing)
Most other microprocessors can access all of memory at any time: "flat memory
o addresses are relative to segment registers
o segments may overlap
Storage is Little-Endian
8086 CPU is split into two main parts
o Execution Unit
o Bus Interface Unit
Status Flags Register
O = Overflow Z = Zero
D = Direction A = Aux. Carry
I = Interrupt P = Parity
T = Trap C = Carry
S = Sign
A Machine Code Program
0000 2B C0
0002 03 07
0004 83 C3 02
0007 3B D3
0009 79 F7
2B C0 =0010 1011 1100 0000
Format of register-to-register instruction:
opcode = 001010 means "Subtract"
w = 1 means "word" (16 bits); 0 means "byte"
dest reg = address of destination register: 000 = AX
src reg = address of source register: 000 = AX
ASSEMBLY LANGUAGE PROGRAM
Written using mnemonics and comments
0000 SUB AX,AX ;Set AX to 0
0002 ADD AX,[BX] ;add (word pointed to by BX) to AX
0004 ADD BX,2 ;Add 2 to BX (points to next word)
0007 CMP DX,BX ;Compare DX to BX
0009 JNS 0002 ;If DX >= BX jump back to 0002
Adds up contents of memory from [BX] to [DX], result goes in AX
CMP - COMPARE
Subtracts source from destination and updates flags
does not save result.
Flags can subsequently be checked for conditions
CMP DX, BX performs (DX - BX)
So if BX > DX result will be negative - Sign bit will be set
Test/Compare instructions set flags
Flags may affect later instructions (eg. Conditional jumps)
JNS - JUMP IF NOT SIGNED
Jumps to new address if Sign flag = 0
0009 79 F7 JNS 0002
79 means "JNS"
How does "F7" take us back to 0002...?
F7 = 1111 0111
2's complement... MSB=1 so NEGATIVE
Invert: 0000 1000
Add 1: 0000 1001 = 9 (dec)
Therefore 1111 0111 (F7) is -9
After fetching "79 F7" Instruction Pointer = 000B
Adding -9 to IP gives 0002
First, lets learn how to move data to a register:
To move data to a register you use the mov command. Where the data is to go is the first
item, and the data is the second item. Here is an example that MOVes 45 to AX:
Let's try assembling it: Type mov ax,45 into asm.txt and save it. Drag asm.txt over
A86.com and drop it to assemble. A86.com will run and create 2 new files. The .sym file
is of no use to us and can be deleted. However, the .com file is the program. Don't try
running the .com file, because it WILL crash because we didn't end the program properly.
That is how to assemble a file.
Now, let's move data from one register to another: We still use the mov command , and
time the register to receive the data is first and the register with the data to move is
second, here is an example:
The first line moves 45(h after a number means hex) into ax, the second copies the
number in ax (45h) to bx, so bx is now 45h too. To mov data around in the split registers
simply replace the large register with the split version. Like this mov ah,cl or mov
dh,90h , however, do not mix large and split registers like this mov ah,ax or it won't
assemble. Using split registers works for add and sub only.
+,-,*,divide (how do you do divide on a keyboard?)
The basic math operations in assembly are:
add - Adds the first item to the second storing result in first item.
sub - Subracts the second item from the first and stores result in the first item.
mul - Multiplies the given item to AX and stores the result in AX.
div - Divides the given item by AX and stores the result in AX.
The add and subtract operations are simple enough, they do their job like a MOV
command and subtract or add to the receiving end and store the result in the receiving
add ax,23 ;adds 23 to ax and stores results in ax.
sub ax,45h ;subtracts 45 in hex from ax and stores in ax.
The mul and div instructions are a bit different though, they both use the AX register as
their "base of operations", They both multiply to or divide by A REGISTER ONLY and
store the result in AX.
mov ax,10 ;give a value to multiply by in AX.
mov bx,20 ;give a register the data we want to * by
mul bx ;multiply ax & bx, storing the result in
mov ax,10 ;What we want to divide or data by.
mov dx,100 ;What we want to be divided by AX.
div dx ;Divide DX by AX, storing result in AX.
And that's how the BASIC Math Operations work. That's right! Basic is italicized
because there are actually two more math operations I have not mentioned yet, and no,
they do not make multiply and divide any easier! Wondering why the explanations of the
example code start with semi-colons? Find out in the next section!
What those semi-colons are for! Those semi-colons are called code comments, they are
useful to document your code so you know what each thing does. The semi-color (;)
stops the assembler from thinking that your comment is assembly code and returning an
error. Comments last until the end of the current line and are considered good
programming practice in large projects. That's all the commenting I have to comment on
Labels and Unconditional Jumps
The goto statement for you Basic Programmers. In this section we start getting into
program flow control. Labels are just what the name suggests labels, the syntax for a
label is like this:
As you can see it is a name and a colon. NO CODE CAN BE ON THE SAME LINE AS
A LABEL! Labels do not actually do anything but sit there and reference a location in a
program. However, they are very useful for Unconditional Jumps, which are used to
JUMP to another location in a program and run the code starting after the label
referenced. Here is an example to best explain Unconditional Jumps:
jmp runhere ;JMP command jumps to the label "runhere" and
run the code after it.
mov ax,45 ; This command won't be run because it is JMPed
runhere: ; The label where the JMP jumps to.
mov ax,90h ; This statement will be run after the jump.
Now I hope that you understand labels and their use with Unconditional Jumps.
Conditional Jumps only jump if a certain condition is met, that's why they are called
conditional! The condition they check is based on the FLAGS. See, I told you the flags
would be important! There are several jump commands that check a certain thing to see
if they should jump or not. They are:
JE - Checks for equality.
JNE - Checks for UNequality.
JA - Checks to see if one thing is Above another.
JB - Checks to see if one thing is Below another.
JZ - Same as JE...
Those are the Conditional Jump Commands. Use them well Young Jedi.
The Compare Command (CMP) compares the first item with the second setting and
clearing flags automatically. The most recent compare is what conditional jumps use.
You can compare two registers like this:
cmp ax,bx ;Compares AX to BX
And Register to Data like this:
cmp dx,45 ;Compares DX to 45
REMEMBER THAT CMP DOESN'T STORE ANYTHING!
Also, remember that the first item is compared TO the second. This command is like
telling the computer to create an equation resulting from the comparison such as DX > 45,
which would make the JA (Jump on Above) jump. Remember in all operations that
registers go on the left and data goes on the right. You can also use the split registers
with the cmp command.
SUGGESTED LIST OF EXPERIM ENTS
1 [Arithmeti c]
Write 8086 Assembly Language programs for the following operations. The
operands and the results are to be stored in specific memory locations.
(a) Add three 16-bit unsigned integers (b)Add three 16-bit signed integers (c)
Multiply two 16-bit unsigned integers (d) Multiply two 16-bit signed integers (e)
Divide a 16-bit unsigned integer by an 8-bit unsigned integer (f)Compute the
X = |((A*B) – (C*D))| /E. Assume 16-bit unsigned integer variables.
2 [Basic Input/Output]
Study the various BIOS interrupts and DOS functi on calls that are useful in
input and output operations. Build programs for multiple character input, multi -
digit input, etc that may be reused in the subsequent programs.
3 [Control Stru ctures ]
Write Assembly Language programs for simulating:
(a) For.. loop (b)While loop (c) Repeat..until loop (d) If ..then..else structure
(e)Switch statement ( of C language). Use appropriate action within the loop such
that the difference among the above control structures is understood.
5 [Subroutines -Use of Sta ck]
(a) Write a subroutine for raising an integer x to an integral power n. Using this
routine, evaluate a polynomial p(x) at x = k. (b)Test whether an input string is a
(a) Write a program to search for a given number in an array of N n um bers. Do
not assume that the array is sorted. Generate appropriate responses after a
success and failure (b) Create a sample login session for a user. Get a User -id
and Password from the keyboard, without echoing the password. Verify the User -
id, passwor d pair using a stored list, and take appropriate action.
7 [Finding M in and M ax of a set of numbers]
Given a set of N integers, find the minimum value in it. Without using an
additional loop, find the maximum value also. Hence find the range of the set
8 [Display Attributes and Speaker control]
Design a menu-driven program for the following display functions
(a) Clear the screen (b) Display the string given by the user at the center of the
screen in a particular color and make it blink (c) Produce a beep soun d after step
b is completed.
9 [M ACRO definition]
Code a MACRO definition to find the GCD of two integers. It should accept two
dummy parameters A and B and produce GCD (A, B). Use the macro for finding
LCM (A, B) also.
Exp 10 Interfa cing
(a) Interface a Digital-to-Analog Converter (DAC) to the 8086-kit and write a
program to display different waveforms (triangular, square, saw tooth, etc) on a
CRO. (b) Interface a Stepper motor interface card to the 8086 kit, and write a
program to control the rotation of the stepper motor.
NOTE TO THE T.A / INSTRUCTOR
An introductory session to the functional blocks of Intel 8086, its
instruction set and the use of MASM/TASM/DEBUG is desirable.
Divide the students into groups of 2-3 people. Assign each group a user-
id and password on a specific machine, which must be used throughout
After login, go to the directory C:/8086/HELPPC on the C drive. Choose
MASM or TASM as the case may be. HELPPC contains the basics of 8086
architecture and its instruction set.
Enter the programs using a text editor, and assemble using TASM/MASM
from the DOS command line. Link the .obj files and execute the resulting
.exe file. Alternately, use the debugger facility to enter, assemble and step
through the program.
After completing each experiment, a demo of the same should be
evaluated. Also insist on regular record submission.
IBM PC Assembly Language and Programming: Peter Abel
Using Assembly Language: Wyatte, Sr.