Manual
Manual
Introduction
1. MASM Overview
MASM, standing for Microsoft Macro Assembler, is a standard assembly tool used for 8086
assembly language programming. First, the assembly language code written using any text
editor such as DOS Edit, or Windows Notepad, is saved as an ASM file (.asm). An object file
(.obj) is generated from the ASM file using MASM. This object file is then fed to a linker to
obtain an executable (.exe) file which may then be tested and debugged using Microsoft
CodeView. Any logical errors found in the program must be fixed and the program
reassembled.
2. Getting Started
1. Create a directory for you use. It would be a good practice to stick to this directory to
save all your 8086 programs throughout the course of your laboratory for this
subject.
4. Open Notepad and type out your program. Save it with a ‘.asm’ extension.
This step will create a .OBJ file of the same filename if your program is error-free,
otherwise it will generate a report of all the syntax errors. These errors must be
fixed in the ASM file, and Step 5 repeated.
7. Finally, type
Dept. of ECE, GAT Page 1
Microprocessor Lab (10ECL68)
> cv/p <filename>.exe (no semicolon this time)
to open up Microsoft CodeView which allows you to test and debug your program.
The various commands usable in CodeView are listed in Section 0.4.
If you’re wondering what “/zi” and “/co” are, they are switches which generate symbolic
information for CodeView. If you skip them, you won’t be able to see the source code for
your program in CodeView.
To see the full list of switches that can be used with MASM and Linker, type the following
commands at the command prompt:
> masm /help
> link /help
The “/p” you’re using with CV displays a page of information in the CodeView window
having 18 lines. If you wish to see a larger window with more lines of code at once, you may
use “cv/43” (43 lines) or “cv/50” (50 lines) instead of “cv/p”.
masm/zi %1.asm;
link/co %1.obj;
cv/p %1.exe
Note that the first two lines end in a semicolon, but not the last line.
2. Save it with the name “compile.bat”. You may use any other filename, but with the
extension .BAT. This file should be in your working directory.
3. The next time you wish to assemble your program (.asm file), simply type the
following at the command prompt.
> compile <filename>
Here, the filename is to be typed without any extension, and you must use the exact
name of the batch file you created earlier (in this case, “compile”).
Doing this will invoke the commands within the batch file – your program will be
automatically assembled, linked and CodeView will be opened if there are no errors.
Syntax errors, if any, will be reported in the assembly stage.
Direct addressing refers to transfer of data (byte/word) between a register and memory
location. Memory-to-memory transfer is not supported by any instruction except MOVS.
The following program moves a byte 11H from memory location ‘mem1’ to register AL,
and then from AL to another memory location ‘mem2’ using direct addressing.
Program 1.1 (a) Byte Transfer Using Program 1.1 (b) Byte Transfer Using
Immediate Addressing Direct Addressing
.model small .model small
.data .data
mem DB ? mem1 DB 11H
.code mem2 DB ?
mov AX,@data .code
mov DS,AX mov AX,@data
mov AL,11H mov DS,AX
mov mem,11H mov AL,mem1
mov AH,4CH mov mem2,AL
int 21H mov AH,4CH
end int 21H
end
Result:
Before Execution: mem = Result:
After Execution: mem = Before Execution: mem2 =
After Execution: mem2 =
Indirect addressing refers to transfer of data (byte/word) between a register and memory
location that is addressed by an index or base register. The index registers are SI and DI,
Dept. of ECE, GAT Page 4
Microprocessor Lab (10ECL68)
and the base registers are BX and BP. It may be recalled that memory-to-memory transfer
is not supported. The following program transfers data from ‘src’ (addressed by SI) to AL,
and then from AL to ‘dest’ (addressed by DI).
Program 1.1 (c) Byte Transfer Using Program 1.1 (d) Byte Transfer Using
Indirect Addressing Mode Base-plus-Index Addressing Mode
.model small .model small
.data .data
src DB 11H array DB 11H,22H,33H,44H,55H
dest DB ? dest DB ?
.code .code
mov AX,@data mov AX,@data
mov DS,AX mov DS,AX
mov SI,OFFSET src mov BX,OFFSET array
mov DI,OFFSET dest mov SI,4
mov AL,[SI] mov AL,[BX+SI]
mov [DI],AL mov BX,OFFSET dest
mov AH,4CH mov DI,0
int 21H mov [BX+DI],AL
end mov AH,4CH
int 21H
Result: end
Result:
Here, index registers SI and DI are used to directly address array[0] (source) and array[N]
(destination). A loop is run N times, and in each iteration, 1 byte of data is copied form [SI]
to [DI], and then SI and DI are incremented.
The program 1.2(a) above has been redone here, but this time using register-relative
addressing mode (memory is addressed relative to a register i.e. the register holds the
displacement only). The index registers SI and DI simply hold the displacements
rather than the complete addresses of the source and destination respectively, and memory
is addressed using these registers as array indexes.
Program 1.2 (a) Block Transfer (without Program 1.2 (b) Block Transfer (without
Overlap) using Index Addressing Mode Overlap) using Register-relative
Addressing Mode
.model small .model small
.data .data
Result: Result:
Before Execution: array = Before Execution: array =
After Execution: array = After Execution: array =
2. Arithmetic Operations
2.1. Addition of Multiprecision Numbers
8086 performs arithmetic on 8/16-bit numbers only, but can be forced to do the same on
higher bit numbers, called multiprecision numbers, using appropriate programs.
Our objective is to add two 48-bit numbers: 104563F25AC3H and F9032985F4DCH. The
expected sum is 109488D784F9FH. We may achieve this using one of the two methods
described below:
10 45 63 F2 5A C3 H
+ F9 03 29 85 F4 DC H
-------------------------------------
01 09 48 8D 78 4F 9F H
Addition is performed using an 8-bit register, such as AL.
Carry after each addition is propagated through the use of ADC (add with carry).
2.2. Multiplication
8086 can perform both 8-bit and 16-bit multiplication. The product generated is always
double-sized, i.e. 8-bit multiplication generates a 16-bit product, while 16-bit multiplication
generates a 32-bit product.
8-bit multiplication
The multiplier (8-bit) is held in AL
The multiplicand (8-bit) may be held in any register or memory location
The product generated is 16-bit, and held in AX
16-bit multiplication
The multiplier (16-bit) is held in AX
The multiplicand (16-bit) may be held in any register or memory location
The product generated is 32-bit, and held in DX, AX
DX holds the higher word while AX holds the lower word of the product
Our objective is to multiply two 16-bit numbers: 2A58H and FB6DH, but this time using
the instruction IMUL. Their unsigned values are 10840 and 64365 respectively; thus when
multiplied, the expected product is 10840 x 64365 = 697716600 = 29964F78H.
Our objective is to multiply the same two 16-bit numbers: 2A58H and FB6DH. Their signed
values are +10840 and –1171 respectively; thus when multiplied, the expected product is
+10840 x –1171 = –12693640 = FF3E4F78H.
Please note that the product generated is 32-bit and the range of 32-bit signed numbers is 0
to 232–1.
2.3. Division
As with multiplication, division is possible on both 8-bit and 16-bit signed and unsigned
numbers. In any division operation, the dividend must be double sized i.e. in 8-bit division
the dividend must be 16-bit, while in 16-bit division, the dividend must be 32-bit.
8-bit division
Divisor is 8-bit, and may be in any 8-bit register or memory location.
Dividend must be 16-bit, and should be loaded into AX.
If dividend is 8-bit, it can be loaded into AL, and AH must be filled depending on
whether the number is signed or unsigned.
Program 2.3 (a) 8-bit Unsigned Division Program 2.3(b) 8-bit Signed Division
.model small .model small
.data .data
divd DW 0A132H divd DW 3ABH
divs DB 64H divs DB 0D3H
res DW ? res DW ?
.code .code
mov AX,@data mov AX,@data
mov DS,AX mov DS,AX
mov AL,divs mov AL,divs
mov AH,0 cbw
mov BX,AX mov BX,AX
mov AX,divd mov AX,divd
div BX cwd
mov res[0],AX idiv BX
mov res[2],DX mov res[0],AX
mov AH,4CH mov res[2],DX
int 21H mov AH,4CH
end int 21H
end
Result:
Result:
16-bit division
Divisor is 16-bit, and may be in any 16-bit register or memory location.
Dividend must be 32-bit, and should be loaded into DX, AX – DX must contain the
higher word.
If dividend is 16-bit, it can be loaded into AX, and DX must be filled depending on
whether the number is signed or unsigned.
Dept. of ECE, GAT Page 13
Microprocessor Lab (10ECL68)
If the number is unsigned, DX must be cleared to 0000H.
If the number is signed, DX must be filled with the sign bits of AX (sign-
extension). The instruction CWD (convert word to double word) must be
used to do this.
After division, the remainder is found in DX, and the quotient in AX.
Program 2.3 (c) 16-bit Unsigned Division Program 2.3 (d) 16-bit Signed Division
.model small .model small
.data .data
divd DW 0D0A5H divd DW 0D0A5H
divs DW 56H divs DW 56H
res DW ? res DW ?
.code .code
mov AX,@data mov AX,@data
mov DS,AX mov DS,AX
mov AX,divd mov AX,divd
mov DX,0 cwd
div divs idiv divs
mov res[0],AX mov res[0],AX
mov res[2],DX mov res[2],DX
mov AH,4CH mov AH,4CH
int 21H int 21H
end end
Result: Result:
Program 3.1 (a) BCD Addition and DAA Program 3.1 (b) BCD Subtraction and DAS
.model small .model small
.code .code
mov BX,3099H mov BX,3099H
mov DX,1028H mov DX,1028H
mov AL,BL mov AL,BL
add AL,DL sub AL,DL
daa das
mov CL,AL mov CL,AL
mov AL,BH mov AL,BH
adc AL,DH sbb AL,DH
daa das
mov CH,AL mov CH,AL
mov AH,4CH mov AH,4CH
int 21H int 21H
end end
Result: Result:
Sum: CX=4127H (1028H+3099H=4127H) Difference: CX=071H (3099H–1028H =2071H)
Why ASCII?
You forget that a digital system understands only binary. Therefore, it is necessary that each
character be represented by a unique binary sequence. ASCII uses an 8-bit binary sequence
ranging from 00H to FFH to represent 256 characters, including invisible characters (e.g.
white space and carriage return) and other special characters, apart from the usual
alphabets (A-Z, a-z), digits (0-9) and punctuators (comma, full stop, apostrophe etc.) and
mathematical symbols (+ – * / % etc.).
The AAA instruction works by producing the unpacked BCD result of the decimal sum in
the AX register. This instruction clears AH if the result is less than 10 decimal, and adds a 1
to AH if the result is greater than 10.
Program 3.2 (a) ASCII Addition and AAA Program 3.2 (b) ASCII Subtraction and AAS
.model small .model small
.data .data
num1 DB 05H,08H num1 DB 05H,08H
num2 DB 07H,06H num2 DB 07H,06H
ascii DW ? ascii DW ?
.code .code
mov AX,@data mov AX,@data
mov DS,AX mov DS,AX
mov AH,00H mov AH,00H
mov AL,num1 mov AL,num1
add AL,num2 sub AL,num2
aaa aas
mov DL,AL mov DL,AL
mov AL,num1+1 mov AL,num1+1
adc AL,num2+1 sbb AL,num2+1
aaa aas
mov DH,AL mov DH,AL
mov AX,00H add DX,3030H
adc AX,3030H mov AX,00H
add DX,3030H adc AX,3030H
mov ascii,DX mov ascii,DX
mov ascii+2,AX mov ascii+2,AX
mov AH,4CH mov AH,4CH
int 21H int 21H
end end
Result: Result:
Sum: Difference:
In the above program, AAM transformed the contents of AX register from 002AH to
0402H. The AAM instruction accomplished this conversion by dividing AX by 0AH, and
then storing the remainder in AL and quotient in AH.
In fact, the AAM instruction converts binary numbers to unpacked BCD. This works
only for binary numbers in the range 0000H to 0063H appearing in the AX register.
For example, if the AX register contains 0060H before AAM, it will contain 0906H after
execution of AAM. This is the unpacked BCD equivalent of 96 decimal (60H = 96). If 3030H
is added to 0906H, the result changes to ASCII code.
In the above program, AAD transformed the contents of AX register from 0704H to 004AH.
The AAD instruction accomplished this conversion by multiplying AH by 0AH, and then
adding AL to it and storing the result back in AX.
So it may be seen that AAD is the exact opposite of AAM. The AAD instruction converts
unpacked BCD numbers to binary. This works only for BCD numbers 0 to 99 in unpacked
form (0000H to 0909H) appearing in the AX register.
For example, if the AX register contains 0906H before AAD, it will contain 0060H after
execution of AAD. This is the binary equivalent of 96 BCD (96 = 60H). This binary (hex)
number can now be used as dividend in a division operation.
Program 3.2 (c) ASCII Multiplication and Program 3.2 (d) ASCII Division and
AAM AAD
model small .model small
.data .data
num1 DB 06H divd DW 0704H
num2 DB 07H divs DB 09H
ascii DW ? ascii DW ?
.code .code
mov AX,@data mov AX,@data
mov DS,AX mov DS,AX
mov AH,00H mov AX,divd
mov AL,num1 aad
mul num2 div divs
aam add AX,3030H
add AX,3030H mov ascii,AX
mov ascii,AX mov AH,4CH
mov AH,4CH int 21H
int 21H end
end
Result: ascii = DX,AX = 3238H
Result: ascii = AX = 74 ÷ 9
=> Quotient=AX=8
Reminder=DX=2
4. Code Conversions
By “unpacking”, we mean to separate out all the digits of the given number. For decimal
numbers, this is done by successively dividing by 10, and taking out the remainder after
each division. The process is continued till the quotient is zero. For example, the decimal
number 2805 (Two thousand eight hundred and five) can be unpacked as shown below:
START
1. 2805 ÷ 10 = 280, with remainder = 5 10 2805
2. 280 ÷ 10 = 28, with remainder = 0 10 280 – 5
3. 28 ÷ 10 = 2, with remainder = 8 10 28 – 0
4. 2 ÷ 10 = 0, with remainder = 2 10 2 – 8
STOP 0 – 2
For example, the binary number 17EDH is converted to 6125 BCD (17ED16 = 612510) as
shown below:
First, the binary number is unpacked by successive division by 0AH.
START
After unpacking, we’re left with the individual (hex) digits 6, 1, 2 and 5. These digits must
be multiplied by powers of 10H and summed up to give 6125H (=6125 BCD).
Thus we’ve converted 17ED into 6125 and accomplished binary to BCD conversion.
In the first half of the program, the given binary number, “bin” = 17EDH, is loaded onto AX
as dividend and is unpacked by successive division by 0AH. Each of the remainders is
pushed onto the stack, and division continues with the quotient in AX acting as the next
dividend. Note that it is important to clear DX in order to perform 16-bit division (refer
Section 2.5(d)). At the end of 4 divisions (count = 4), quotient is zero, and hence division is
stopped. At this point, the stack contains all the remainders, with the last remainder (most
significant digit) on top of the stack.
In the next half of the program, the remainders are popped out of the stack one by one and
multiplied by the corresponding power of 10H. The highest power of 10H required is 3,
which is one less than the count, and hence the statement “dec CX”. CX holds the current
power of 10H required, and exponentiation of 10H is achieved by repeated multiplication.
Note that the “loop” statement causes CX to go to zero, and hence CX must be reloaded with
“count – 1” for every iteration. During the last iteration, when CX = 0, no multiplication
with 10H is required – instead the last remainder must be directly added to the BCD result.
When count goes to zero, multiplication stops, and the final result is ready in the DI register
and is saved in the reserved memory location “bcd”.
Note that the input range of the above program is restricted between 0000H–270FH,
since 270F16 = 999910, which is the largest BCD number that can be represented in 16-bits.
Program 4.1 (a) 16-bit Binary to BCD Program 4.1 (b) 8-bit Binary to BCD
.model small .model small
.stack 64H .data
.data bin DB 61H
bin DW 17EDH bcd DB ?
bcd DW ? .code
count DW ? mov AX,@data
.code mov DS,AX
mov AX,@data mov AL,bin
mov DS,AX mov AH,0
mov AX,bin mov BL,0AH
mov count,0 div BL
mov BX,0AH mov CL,AH
unpack: mov DX,0 mov BL,10H
div BX mul BL
push DX add AL,CL
inc count mov bcd,AL
cmp AX,0 mov AH,4CH
jnz unpack int 21H
mov DI,0 end
mov BX,10H Result:
repack: mov CX,count
dec CX
pop AX
jcxz skip
repmul: mul BX
loop repmul
skip: add DI,AX
dec count
jnz repack
mov bcd,DI
mov AH,4CH
int 21H
end
Result:
4.2. BCD to Binary Conversion
Earlier, we converted the binary number 17EDH to 6125 BCD (17ED16 = 612510). Now, let
us attempt the reverse:
START
1. 6125H ÷ 10H = 612H, with remainder = 5H 10H 6125H
2. 612H ÷ 10H = 61H, with remainder = 2H 10H 612H – 5H
3. 61H ÷ 10H = 6H, with remainder = 1H 10H 61H – 2H
4. 6H ÷ 10H = 0, with remainder = 6H 10H 6H – 1H
STOP 0 – 6H
After unpacking, we’re left with the individual (bcd) digits 6, 1, 2 and 5. These digits are
multiplied by powers of 0AH and summed up to give 17EDH.
So we’ve successfully reversed the conversion, and obtained back 17ED from 6125 and
achieved BCD to binary conversion. Program 4.2(a) does the same.
This program is very much the same as 4.1(a) with two small changes – 0AH and 10H have
been swapped to perform reverse conversion, and the labels “bin” and “bcd” have been
interchanged as well.
Program 4.2 (a) 16-bit BCD to Binary Program 4.2 (b) 8-bit BCD to Binary
.model small .model small
Result:
5. Applied Arithmetic
5.1. Square of an 8-bit Unsigned Binary Number
Square of an 8-bit binary number may be directly calculated by multiplying the number
with itself. Of course, the resultant product will be double-width (16-bit) as is the case with
any multiplication on 8086.
To carry out signed squaring, we need to use IMUL in place of MUL. In that case, (FFH)2 will
result in 0001H, since (–1)2 = 1, where –1 is the signed value of FFH.
Program 5.1 Square of an 8-bit unsigned Program 5.2 Cube of an 8-bit unsigned
Binary number Binary number
.model small .model small
.data .data
num DB 0FFH num DB 0FFH
square DW ? cube DW 2 dup(0)
.code .code
mov AX,@data mov AX,@data
mov DS,AX mov DS,AX
mov AL,num mov AL,num
mul AL mov BL,AL
mov square,AX mul BL
mov AH,4CH mov BH,0
int 21H mul BX
end mov cube,AX
mov cube+2,DX
Result: square = AX = mov AH,4CH
int 21H
end
For the sake of simplicity, let us limit the size of our factorial to 16-bits. This means that the
highest input possible is 8, since the factorial of 9 is 362880 10 = 58980H, which exceeds 16-
bits.
Program 5.3 Factorial
.model small
.data
num DW 5H
fact DW ?
.code
mov AX,@data
mov DS,AX
mov AX,0001H
mov CX,num
jcxz skip
back: mul CX
loop back
skip: mov fact,AX
mov AH,4CH
int 21H
end
Result: fact = AX =
It should be understood that the LOOP instruction takes care of both decrementing CX and
jumping back. The statement “loop <label>” is a combination of “dec CX” and “jnz <label>”.
For example, to find the LCM of 24 and 32, we will divide all the multiples of 24 by 32 until
the remainder is zero:
It is obvious that you’ll arrive at the same LCM even when you divide multiples of 32 by 24.
In fact, this will be quicker (3 steps instead of 4).
The program below performs the same operations as in the table above. First, one of the
two numbers is put into the accumulator AX and the other into BX. The accumulator is zero
extended into DX to be able to perform 16-bit division. Next, before division, AX and DX are
stored on the stack. Division then determines whether the remainder is zero or not. If it is,
the operation is stopped and the current stack contents are saved as the LCM. If not, the
saved contents from the stack are put back into AX and DX and num1 is added to AX to
produce the next multiple, and DX is incremented in case of a carry. The program then
loops back to the next division.
If you’re interested, you can improve the efficiency of the above program by adding code to
check for the larger of the two numbers num1 and num2. Whichever turns out to be larger
may then be loaded into AX. This will reduce the number of steps required to determine the
LCM, and the reduction will be especially drastic when one of the numbers is far greater
than the other.
Program 5.4 LCM of Two Numbers Program 5.5 GCD of Two Numbers
.model small .model small
.stack 64H .data
.data num1 DW 24D
num1 DW 24D num2 DW 32D
num2 DW 32D gcd DW ?
lcm DW 2 dup(0) .code
.code mov AX,@data
mov AX,@data mov DS,AX
mov DS,AX mov AX,num1
mov AX,num1 mov BX,num2
mov BX,num2 next: mov DX,0
mov DX,0 div BX
rpt: push AX cmp DX,0
push DX je exit
div BX mov AX,BX
cmp DX,00H mov BX,DX
je exit jmp next
pop DX exit: mov gcd,BX
pop AX mov AH,4CH
add AX, num1 int 21H
jnc skip end
inc DX
skip: jmp rpt Result: gcd = BX =
exit: pop lcm[2]
pop lcm
mov AH,4CH
int 21H
end
6. Bit Manipulation
Dept. of ECE, GAT Page 30
Microprocessor Lab (10ECL68)
Program 6.1 To Check if the given Byte of Program 6.2 To Check if the given Byte of
data is Even or Odd data is Positive or Negative
.model small .model small
.data .data
num DB 71H num DB 80H
res DB ? res DB 00H
.code .code
mov AX,@data mov AX,@data
mov DS,AX mov DS,AX
mov AL,num mov AL,num
ror AL,01H rol AL,01H
jnc even jnc exit
odd: mov res,0FFH minus:mov res,0FFH
jmp exit exit: mov AH, 4CH
even: mov res,00H int 21H
exit: mov AH,4CH end
int 21H
end Result: res =
Result: res =
To see if a given byte is a valid 2-out-of-5 code, we have to check if it satisfies the above two
conditions. To check if its first 3 bits contain 0’s, we mask the remaining bits by ‘and’ing
with 11100000 (E0H), and then check if the result is 00000000 (00H). This is done by the
For example, 00011000 (18H), 00001001 (09H), 00000110 (06H) etc. are valid 2/5
codes.
Program 6.3 To Count the number of 1’s Program 6.4 To Check if the given Byte of
and 0’s in the given Word of data data is a valid 2/5 code or not
.model small .model small
.data .data
num DW 8421H num DB 18H
ones DB 0 res DB 00H
zeros DB 0 .code
.code mov AX,@data
mov AX,@data mov DS,AX
mov DS,AX mov AL,num
mov AX,num test AL,0E0H
mov BX,00H jne exit
mov CX,16 mov CX,05H
back: ror AX,1 mov BL,00H
jnc zero back: ror AL,1
one: inc ones jnc skip
jmp skip inc BL
zero: inc zeros skip: loop back
skip: loop back cmp BL,02H
mov AH,4CH jne exit
int 21H mov res,0FFH
end exit: mov AH,4CH
int 21H
Result: ones = end
zeros =
Result: res =
Basically, a byte will be a bitwise palindrome when its first and last bits, second and second-
last bits etc. are the same. This is checked using four TEST instructions. For example, “test
AL, 81H” masks all the bits of AL except the MSB and LSB. The result (which is stored in a
temporary register) is then checked for parity. For it to be a bitwise palindrome, the
unmasked bits must be equal, either both zeros (0××××××0) or both ones (1××××××1), i.e.
it must show even parity. If it shows odd parity, then it is of the form 0××××××1 or
1××××××0, in which case it fails to be a bitwise palindrome. Observe that the program
jumps to “no” if in any stage the unmasked bits exhibit odd parity. Only a byte which
succeeds all four tests is declared as a valid bitwise palindrome.
In the above program, let us assume data input is of the form WXYZH. Now, for it to be a
nibblewise palindrome, W must be equal to Z, and X equal to Y. To be able to verify this, we
make 2 copies of the data, in AX and BX. We ‘and’ AX with 0F0FH to be left with 0X0ZH.
Next, we rotate BX by 4 bits (= 1 hex digit) to the left. Since rotation circulates the data, BX
becomes XYZWH. BX is then ‘and’ed with 0F0FH to give 0Y0WH. Then, by comparing AX
and BX, we’re seeing if 0X0ZH is equal to 0Y0WH, which will be true if and only if X=Y and
Z=W. Thus we’ll know if the given number is a nibblewise palindrome or not.
Program 6.5 To Check if the given Byte of Program 6.6 To Check if the given Word of
Result:
7. Array Operations
Dept. of ECE, GAT Page 34
Microprocessor Lab (10ECL68)
7.1. Addition of N Numbers
We’ll be given an array of N numbers, are we’re required to sum up all its elements. This can
be done as in the two programs below. Program 7.1(a) shows how BCD numbers may be
added, while 7.1(b) does the same with HEX numbers.
START
1. Assume the first element in the array to be the largest number. Save array[0] in
accumulator.
2. Set index to the second element, and counter to N–1.
3. Compare current array element with accumulator.
4. If accumulator is larger, skip step 5 and go to step 6.
5. Overwrite accumulator with current array element.
6. Increment array index and decrement counter.
7. If counter is not zero, go back to step 3.
8. Save the accumulator’s contents as the largest array element.
STOP
To find smallest of N numbers, just replace the instruction JNB with JB in the above
program.
Note that we’re using registers CX and DX to maintain the count values of the inner and
outer loops respectively. In this case, N = 4. Therefore we require N–1 = 3 iterations each of
the inner and outer loops.
DX and CX both start equal to 3. CX is decremented with each comparison, and when it
reaches 0, DX is decremented. When DX reaches 0, the sorting is completed.
Notice how at the end of each outer loop one element is positioned in its rightful place. For
example, at the end of the first outer loop, 21 is placed bottommost. By the end of the next
outer loop, 13 is placed above 21. Next 5 goes on top of 13. The last element, 1, is
automatically placed correctly. This is analogous to bubbles rising in a glass of a fizzy drink
– the largest bubbles rise first and take the topmost positions, followed by the medium-
sized ones, and lastly the smallest ones. This is why this sorting technique came to be called
“Bubble” sorting.
The bubble sort program for Descending sort may be obtained from the above program,
just by replacing the instruction JBE (jump if below or equal) with JAE (jump if above or
equal).
Program 7.2 Largest of N numbers Program 7.3 Bubble Sort (Ascending order)
.model small .model small
.data .data
array DB 13H,35H,01H,41H,24H array DB 21H,13H,05H,01H
len DW $-array len DW $-array
res DB ? .code
.code mov AX,@data
mov AX,@data mov DS,AX
mov DS,AX mov DX,len
mov AL,array[0] dec DX
mov SI,1 outloop: mov CX,len
mov CX,len dec CX
dec CX mov SI,OFFSET array
back: cmp AL,array[SI] inloop: mov AL,[SI]
jnb skip cmp AL,[SI+1]
mov AL,array[SI] jbe noswap
skip: inc SI xchg AL,[SI+1]
loop back mov [SI],AL
mov res,AL noswap: inc SI
mov AH,4CH loop inloop
int 21H dec DX
end jnz outloop
mov AH,4CH
Result: res = int 21H
end
Result: array =
8. String Operations
8.1. String Transfer
A ‘string’ refers to a continuous sequence of memory locations containing a long stream of
data – in other words, an array. Specifically, a string refers to an array of ASCII data. A string
may be declared either as a sequence of characters enclosed within single quotes (str DB
‘abcdef’), or as a byte sequence of equivalent ASCII characters (str DB 61H, 62H, 63H,
64H, 65H, 66H).
In the following program, our objective is to transfer (copy) the given string ‘str1’ to
another memory location ‘str2’. This could have been done as in Program 1.4, but now we
will be using the string-move function MOVS (MOVe String). More specifically, we will be
using MOVSB (MOVe String Byte), since ASCII characters here are stored as bytes.
First, the address of the data segment is copied to both DS and ES registers. The source and
destination pointers SI and DI are also initialized. Thus the source of the string transfer will
be DS:SI, while its destination will be ES:DI. The instruction CLD clears the direction flag,
i.e. DF = 0, thus setting the string transfer in ‘auto-increment’ mode. This means that SI
and DI will automatically incremented after each byte transfer. The instruction MOVSB
transfers only one byte from DS:SI to ES:DI. Therefore, it is prefixed with REPNZ so that it
may be repeated until CX = 0.
The statement ‘len DB $-str1’ must immediately follow the declaration of str1, otherwise
the value of ‘len’ will be incorrect.
In the following program, the given string ‘str’ must be tested to see if any location contains
the byte defined by ‘key’. As seen here, the SCASB instruction has a REPNE (REPeat while
Not Equal) prefix. The REPNE prefix causes the SCASB instruction to repeat until either CX
register reaches 0, or until an equal condition if found in any of the comparisons. Note that
the prefix causes CX to decrement without affecting any of the flag bits.
The SCASB instruction and the comparisons it makes changes the makes changes the flag
bits. The zero flag is set when SCASB finds the search element in the given string.
If the length of the string is ‘len’, then the last element is obviously the (len–1)th element.
Two pointers, SI and DI, point to the first (0th)and last elements respectively. The contents
of their memory locations are exchanged, and then SI is incremented, while DI is
decremented. This process is continued until the pointers reach half length.
One thing you mustn’t fail to notice in the above program is the use of the assembler
directive EQU. Instead of the usual ‘len DW $-str’, here we’ve used ‘len EQU $-str’, because
DW defines variables, while EQU defines constants. To be able to assign the value (len/2)
to ‘halflen’, MASM needs ‘len’ to be a constant, not a variable. So ‘len DW $-str’ will not
work in this case, and instead we’d have to use ‘len EQU $-str’.
Result:
Result:
Result: Result:
9.6) 8086 ALP TO WRITE INTO A FILE 9.7) 8086 ALP TO READ FROM A FILE
Experiments on interfacing 8086 with the following interfacing modules through DIO
(Digital Input/output – PCI bus compatible) card.
1) 1. Program to rotate the stepper motor in clock-wise and anti-clock wise direction
.model small rol al,01h
.code loop back1
mov dx,020e3h mov ah,4ch
mov al,80h int 21h
out dx,al delay proc
mov cx,400 push cx
mov al,88h mov bx,0ff0h
back: mov dx,020e0h l2: mov cx,099ffh
out dx,al l1: loop l1
call delay dec bx
ror al,01h jnz l2
loop back pop cx
mov cx,200 ret
mov al,88h delay endp
back1:mov dx,020e0h end
out dx,al
call delay Result:
Result: