Block 4 PDF
Block 4 PDF
Block 4 PDF
ARCHITECTURE
Structure Page No.
1.0 Introduction 5
1.1 Objectives 5
1.2 Microcomputer Architecture 5
1.3 Structure of 8086 CPU 7
1.3.1 The Bus Interface Unit
1.3.2 Execution Unit (EU)
1.4 Register Set of 8086 11
1.5 Instruction Set of 8086 13
1.5.1 Data Transfer Instructions
1.5.2 Arithmetic Instructions
1.5.3 Bit Manipulation Instructions
1.5.4 Program Execution Transfer Instructions
1.5.5 String Instructions
1.5.6 Processor Control Instructions
1.6 Addressing Modes 29
1.6.1 Register Addressing Mode
1.6.2 Immediate Addressing Mode
1.6.3 Direct Addressing Mode
1.6.4 Indirect Addressing Mode
1.7 Summary 33
1.8 Solutions/Answers 33
1.0 INTRODUCTION
In the previous blocks of this course, we have discussed concepts relating to CPU
organization, register set, instruction set, addressing modes with a few examples. Let
us look at one microprocessor architecture in regard of all the above concepts. We
have selected one of the simplest processors 8086, for this purpose. Although the
processor technology is old, all the concepts are valid for higher end Intel processor.
Therefore, in this unit, we will discuss the 8086 microprocessor in some detail.
1.1 OBJECTIVES
After going through this unit, you should be able to:
• describe the features of the 8086 microprocessor;
• list various components of the 8086 microprocessor; and
• identify the instruction set and the addressing modes of the 8086 microprocessor.
Bus Sizes
1. The Address bus: 8085 microprocessor has 16 bit lines. Thus, it can access up to
216 = 64K Bytes. The address bus of 8086 microprocessor has a 20 bits address
bus. Thus it can access upto 220 = 1M Byte size of RAM directly.
2. Data bus is the number of bits that can be transferred simultaneously. It is 16 bits
in 8086.
Microprocessors
The microprocessor is a complete CPU on a single chip. The main advantages of the
microprocessor are:
• More throughput
• More addressing capability
• Powerful addressing modes
• Powerful instruction set
• Faster operation through pipelining
• Virtual memory management.
However, RISC machine do not agree with above principles.
6
Microprocessor
The assembly language for more advanced chips subsumes the simplest 8086/ 8088 Architecture
assembly language. Therefore, we will confine our discussions to Intel 8086/8088
assembly language. You must refer to the further readings for more details on
assembly language of Pentium, G4 and other processors.
while (1)
{
fetch (instruction); ,
execute (using date);
}
7
Assembly Language
Programming
The word independent implies that these two units can function parallel to each other.
In other words they may be considered as two stages of the instruction pipeline.
The BIU (Bus Interface Unit) primarily interacts with the system bus. It performs
almost all the activities relating to fetch cycle such as:
• Reading or writing data memory or I/O port from memory or Input/ Output.
The instruction/ data is then passed to the execution unit. This BIU consists of:
The instruction queue is used to store the instruction “bytes” fetched. Please
note two points here: that it is (1) A Byte (2) Queue. This is used to store
information in byte form, with the underlying queue data structure. The
advantage of this queue would only be if the next expected instructions are
fetched in advance, thus, allowing a pipeline of fetch and execute cycles.
These are very important registers of the CPU. Why? We will answer this later.
In 8086 microprocessor, the memory is a byte organized, that is a memory
address is byte address. However, the number of bits fetched is 16 at a time. The
segment registers are used to calculate the address of memory location along
with other registers. A segment register is 16 bits long.
The BIU contains four sixteen-bit registers, viz., the CS: Code Segment, the DS:
Data Segment, the SS: Stack Segment, and the ES: Extra Segment. But what is
the need of the segments: Segments logically divide a program into logical
entities of Code, Data and Stack each having a specific size of 64 K. The
segment register holds the upper 16 bits of the starting address of a logical
group of memory, called the segment. But what are the advantages of using
segments? The main advantages of using segments are:
• The addresses that need to be used in programs are relocatable as they are
the offsets. Thus, the segmentation supports relocatability.
• Although the size of address, is 20 bits, yet only the maximum segment
size, that is 16 bits, needs to be kept in instruction, thus, reducing
instruction length.
8
Microprocessor
Architecture
Although the size of each segment can be 64K, as they are overlapping segments we
can create variable size of segments, with maximum as 64K. Each segment has a
specific function. 8086 supports the following segments:
As per model of assembly program, it can have more than one of any type of
segments. However, at a time only four segments one of each type, can be active.
The 8086 supports 20 address lines, thus supports 20 bit addresses. However, all the
registers including segment registers are of only 16 bits. So how may this mapping of
20 bits to 16 bits be performed?
You can add offset of 16 bits (4 Hex digits) from 0000h to FFFFh to it . Thus, a
typical segment which starts at a physical address 10000h will range from 10000h to
1FFFFh. The segment register for this segment will contain 1000H and offset will
9
Assembly Language
Programming
range from 0000h to FFFFh. But, how will the segment address and offset be added to
calculate physical address? Let us explain using the following examples:
Example 1 (In the Figure above)
The value of the stack segment register (SS) = 6000h
The value of the stack pointer (SP) which is Offset = 0010h
SS 6 0 0 0 0 Implied zero
SP + 0 0 1 0
6 0 0 1 0
Physical Address
Example 2
The offset of the data byte = 0020h
The value of the data segment register (DS) = 3000h
Physical address of the data byte
DS 3 0 0 0 0 Implied Zero
Offset + 0 0 2 0
Physical Address
3 0 0 2 0
Example 3
The value of the Instruction Pointer, holding address of the instruction = 1234h
The value of the code segment register (CS) = 448Ah
Physical address of the instruction
CS 4 4 8 A 0 ImpliedZero
+ 1 2 3 4
IP
Physical Address 4 5 A 0 4
10
Microprocessor
1.3.2 Execution Unit (EU) Architecture
Execution unit performs all the ALU operations. The execution unit of 8086 is of 16
bits. It also contains the control unit, which instructs bus interface unit about which
memory location to access, and what to do with the data. Control unit also performs
decoding and execution of the instructions. The EU consists of the following:
(a) Control Circuitry, Instruction Decoder and ALU
The 8086 control unit is primarily micro-programmed control. In addition it has an
instruction decoder, which translates an instruction into sequence of micro operations.
The ALU performs the required operations under the control of CU which issues the
necessary timing and control sequences.
(b) Registers
All CPUs have a defined number of operational registers. 8086 has several general
purpose and special purpose registers. We will discuss these registers in the following
sections.
AX register is also known as accumulator. Some of the instructions like divide, rotate,
shift etc. require one of the operands to be available in the accumulator. Thus, in such
instructions, the value of AX should be suitably set prior to the instruction.
BX register is mainly used as a base register. It contains the starting base location of a
memory region within a data segment.
You will experience their usage in various assembly programs discussed later.
Segment Registers
Segment Registers are used for calculating the physical address of the instruction or
memory. Segment registers cannot be used as byte registers.
Flags Register
A flag represents a condition code that is 0 or 1. Thus, it can be represented using a
flip- flop. 8086 employs a 16-bit flag register containing nine flags. The following
table shows the flags of 8086.
12
Microprocessor
(c) The Source Index (SI) and Destination Index(DI) registers in 8086 can also be Architecture
used as general registers.
Please note that NEXT is the label field. It is giving an identity to the statement. It is
an optional field, and is used when an instruction is to be executed again through a
LOOP or GO TO. ADD is symbolic op-code, for addition operation. AL and BL are
the two operands of the instructions. Please note that the number of operands is
dependent upon the instructions. 8086 instructions can have zero, one or two
operands. An operand in 8086 can be:
1. A register
2. A memory location
3. A constant called literal
4. A label.
Comments in 8086 assembly start with a semicolon, and end with a new line. A long
comment can be extended to more than one line by putting a semicolon at the
beginning of each line. Comments are purely optional, however recommended as they
provide program documentation. In the next few sections we look at the instruction set
of the 8086 microprocessor. These instructions are grouped according to their
functionality.
18
Microprocessor
masking off the upper nibble of each ; and 7 CH = 09h Architecture
byte. Then ADD instruction is used to AAD
convert the unpacked BCD digits in ; adjust to binary before
AL and AH registers to adjust them to ; division AX= 0043 =
equivalent binary prior to division. ; 043h = 67 Decimal
Such division will result in unpacked DIV CH
BCD quotient and remainder. The PF, ; Divide AX by unpacked
SF, ZF flags are updated, while the ; BCD in CH
AF, CF, and the OF flags are left ; AL = 07 unpacked BCD
undefined. ; AH = 04 unpacked BCD
; PF = SF = ZF = 0
CBW Fill upper-byte or word with copies ; AL = 10011011 = -155
of sign bit of lower bit. This is called ; decimal AH = 00000000
sign extension of byte to word. This CBW ;convert signed
instruction does not change any ; byte in AL to signed
flags. This operation is done with AL ; word in AX = 11111111
register in the result being stored in ; 10011011 = -155 decimal
AX.
CWD Fill upper word or double word with ; DX : 0000 0000 0000 0000
sign bit of lower word. This ; AX : 1111 0000 0101 0001
instruction is an extension of the CWD
; DX:AX = 1111 1111 1111 1111:
previous instruction. This instruction
; 1111 0000 0101 0001
results in sign extension of AX
register to DX:AX double word.
CF MSB LSB
CF MSB LSB
CF MSB LSB
CF MSB LSB
(d) TEST instruction performs an OR operation, but does not change the value
of operands.
(e) Suppose AL contains 0110 0101 and CF is set, then instructions ROL AL
and RCL AL will produce the same results.
21
Assembly Language
Programming 1.5.4 Program Execution Transfer Instructions
These instructions are the ones that causes change in the sequence of execution of
instruction. This change can be through a condition or sometimes may be
unconditional. The conditions are represented by flags. For example, an instruction
may be jump to an address if zero flag is set, that is the last ALU operation has
resulted in zero value. These instructions are often used after a compare instruction, or
some arithmetic instructions that are used to set the flags, for example, ADD or SUB.
LOOP is also a conditional branch instruction and is taken till loop variable is below a
certain count.
Please note that a "/" is used to separate two mnemonics which represent the same
instruction.
24
Microprocessor
decremented to zero, Architecture
which means all the
elements of the array are
equal to 0FFh, or an
element in the array is
found which is not equal
to 0FFh. In this case, the
CX register may still be
greater than zero, when the
control comes out. This
can be coded as follows:
(Please note here that you
might not understand
everything at this place,
that is because you are still
not familiar with the
various addressing modes.
Just concentrate on the
LOOPE instruction):
In addition to these instructions, there are other interrupt handling instructions also,
which too transfer the control of the program to some specified location. We will
discuss these instructions in later units.
Well, 8086 only allows you to control certain control flags that causes the processing
in a certain direction, processor synchronization if more than one processors are
attached through LOCK instruction for buses etc.
Note: Please note that these instructions may not be very clear to you right now. Thus,
some of these instructions have been discussed in more detail in later units. You must
refer to further readings for more details on these instructions.
28
Microprocessor
operation occurs in the reverse ; Clear the direction flag Architecture
direction. ; so that the string pointers
; auto-increment.
MOV AX,1000h
MOV DS, AX
; Initialize data segment
; and extra segment
MOV ES, AX
MOV SI, 20h
; Load offset of start of
; source string to SI
MOV DI,30h
; Load offset of start of
; destination string to DI
MOV CX,10
; Load length of string to
; CX as counter
REP MOVSB
; Decrement CX and
; increment
; SI and DI to point to next
; byte, then MOVSB until
; CX = 0
There are many process control instructions other than these; you may please refer to
further reading for such instructions. These instructions include instructions for setting
and closing interrupt flag, halting the computer, LOCK (locking the bus), NOP etc.
30
Microprocessor
default will be assumed to be ; The offsets of these Architecture
in data segment, while LABEL ; variables are calculated
1, will be assumed to be in ; with respect to the
code segment. If we specify, ; segment name (register)
as a direct operand then the ; specified in the
address is non-relocatable. ; instruction.
Please note the value of
segment register will be
known only at the run time.
32
Microprocessor
2. Conditional jump instructions require one of the flags to be tested. Architecture
4. In the instruction MOV BX, DX register addressing mode has been used.
6. In the instruction ADD CX, [DI] [BX] the second operand is a based index
operand, whose effective address is obtained by adding the contents of DI and BX
registers.
1.7 SUMMARY
In this unit, we have studied one of the most popular series of microprocessors, viz.,
Intel 8086. It serves as a base to all its successors, 8088, 80186, 80286, 80486, and
Pentium. The successors of 8086 can be directly run on any successors. Therefore,
though, 8086 has become obsolete from the market point of view, it is still needed to
understand advanced microprocessors.
You can refer to further readings for obtaining more details on INTEL and Motorola
series of microprocessors.
1.8 SOLUTIONS/ANSWERS
Check Your Progress 1
1. It improves execution efficiency by storing the next instruction in the register
queue.
2. (a) False
(b) False
(c) True
(d) False
(e) False
34
Introduction to
UNIT 2 INTRODUCTION TO ASSEMBLY Assembly Language
Unit Name
Programming
LANGUAGE PROGRAMMING
Structure Page No.
2.0 Introduction 35
2.1 Objectives 35
2.2 The Need and Use of the Assembly Language 35
2.3 Assembly Program Execution 36
2.4 An Assembly Program and its Components 41
2.4.1 The Program Annotation
2.4.2 Directives
2.5 Input Output in Assembly Program 45
2.5.1 Interrupts
2.5.2 DOS Function Calls (Using INT 21H)
2.6 The Types of Assembly Programs 51
2.6.1 COM Programs
2.6.2 EXE Programs
2.7 How to Write Good Assembly Programs 53
2.8 Summary 55
2.9 Solutions/Answers 56
2.10 Further Readings 56
2.0 INTRODUCTION
In the previous unit, we have discussed the 8086 microprocessor. We have discussed
the register set, instruction set and addressing modes for this microprocessor. In this
and two later units we will discuss the assembly language for 8086/8088
microprocessor. Unit 1 is the basic building block, which will help in better
understanding of the assembly language. In this unit, we will discuss the importance
of assembly language, basic components of an assembly program followed by
discussions on the program developmental tools available. We will then discuss what
are COM programs and EXE programs. Finally we will present a complete example.
For all our discussions, we have used Microsoft Assembler (MASM). However, for
different assemblers the assembly language directives may change. Therefore, before
running an assembly program you must consult the reference manuals of the
assembler you are using.
2.1 OBJECTIVES
After going through this unit you should be able to:
35
The Central
Processing Unit • It greatly depends on machine and is difficult for most people to write in 0-1
Assembly Language
Programming forms.
• DEBUGGING is difficult.
• Deciphering the machine code is very difficult. Thus program logic will be
difficult to understand.
• Assembly Language provides more control over handling particular hardware and
software, as it allows you to study the instructions set, addressing modes,
interrupts etc.
• Assembly Programming generates smaller, more compact executable modules: as
the programs are closer to machine, you may be able to write highly optimised
programs. This results in faster execution of programs.
Assembly language programs are at least 30% denser than the same programs written
in high-level language. The reason for this is that as of today the compilers produce a
long list of code for every instruction as compared to assembly language, which
produces single line of code for a single instruction. This will be true especially in
case of string related programs.
On the other hand assembly language is machine dependent. Each microprocessor has
its own set of instructions. Thus, assembly programs are not portable.
Assembly language has very few restrictions or rules; nearly everything is left to the
discretion of the programmer. This gives lots of freedom to programmers in
construction of their system.
36
Introduction to
1) Manual assembly Assembly Language
Programming
2) By using an assembler.
Manual Assembly
It was an old method that required the programmer to translate each opcode into its
numerical machine language representation by looking up a table of the
microprocessor instructions set, which contains both assembly and machine language
instructions. Manual assembly is acceptable for short programs but becomes very
inconvenient for large programs. The Intel SDK-85 and most of the earlier university
kits were programmed using manual assembly.
Using an Assembler
The symbolic instructions that you code in assembly language is known as - Source
program.
An assembler program translates the source program into machine code, which is
known as object program.
Mnemonic Machine
Program Assembler Instructions
Step 2: The link step involves converting the .OBJ module to an .EXE machine code
module. The linker’s tasks include completing any address left open by the
assembler and combining separately assembled programs into one executable
module.
The linker:
Step 3: The last step is to load the program for execution. Because the loader knows
where the program is going to load in memory, it is now able to resolve any
remaining address still left incomplete in the header. The loader drops the
header and creates a program segment prefix (PSP) immediately before the
program is loaded in memory.
37
The Central
Processing
AssemblyUnit
Language
Programming
Pass 1: Assembler reads the entire source program and constructs a symbol table of
names and labels used in the program, that is, name of data fields and programs labels
and their relative location (offset) within the segment.
38
Introduction to
Pass 1 determines the amount of code to be generated for each instruction. Assembly Language
Programming
Pass 2: The assembler uses the symbol table that it constructed in Pass 1. Now it
knows the length and relative position of each data field and instruction, it can
complete the object code for each instruction. It produces .OBJ (Object file), .LST
(list file) and cross reference (.CRF) files.
Editor
The editor is a program that allows the user to enter, modify, and store a group of
instructions or text under a file name. The editor programs can be classified in 2
groups.
• Line editors
• Full screen editors.
Line editors, such as EDIT in MS DOS, work with the manage one line at a time. Full
screen editors, such as Notepad, Wordpad etc. manage the full screen or a paragraph
at a time. To write text, the user must call the editor under the control of the operating
system. As soon as the editor program is transferred from the disk to the system
memory, the program control is transferred from the operating system to the editor
program. The editor has its own command and the user can enter and modify text by
using those commands. Some editor programs such as WordPerfect are very easy to
use. At the completion of writing a program, the exit command of the editor program
will save the program on the disk under the file name and will transfer the control to
the operating system. If the source file is intended to be a program in the 8086
assembly language the user should follow the syntax of the assembly language and the
rules of the assembler.
Assembler
An assembly program is used to transfer assembly language mnemonics to the binary
code for each instruction, after the complete program has been written, with the help
of an editor it is then assembled with the help of an assembler.
An assembler works in 2 phases, i.e., it reads your source code two times. In the first
pass the assembler collects all the symbols defined in the program, along with their
offsets in symbol table. On the second pass through the source program, it produces
binary code for each instruction of the program, and give all the symbols an offset
with respect to the segment from the symbol table.
The assembler generates three files. The object file, the list file and cross reference
file. The object file contains the binary code for each instruction in the program. It is
created only when your program has been successfully assembled with no errors. The
errors that are detected by the assembler are called the symbol errors. For example,
List file is optional and contains the source code, the binary equivalent of each
instruction, and the offsets of the symbols in the program. This file is for purely
39
The Central
Processing Unit
documentation purposes. Some of the assemblers available on PC are MASM,
Assembly Language
Programming TURBO etc.
Linker
For modularity of your programs, it is better to break your program into several sub
routines. It is even better to put the common routine, like reading a hexadecimal
number, writing hexadecimal number, etc., which could be used by a lot of your other
programs into a separate file. These files are assembled separately. After each file
has been successfully assembled, they can be linked together to form a large file,
which constitutes your complete program. The file containing the common routines
can be linked to your other program also. The program that links your program is
called the linker.
The linker produces a link file, which contains the binary code for all compound
modules. The linker also produces link maps, which contains the address information
about the linked files. The linker however does not assign absolute addresses to your
program. It only assigns continuous relative addresses to all the modules linked
starting from the zero. This form a program is said to be relocatable because it can be
put anywhere in memory to be run.
Loader
Loader is a program which assigns absolute addresses to the program. These
addresses are generated by adding the address from where the program is loaded into
the memory to all the offsets. Loader comes into action when you want to execute
your program. This program is brought from the secondary memory like disk. The
file name extension for loading is .exe or .com, which after loading can be executed
by the CPU.
Debugger
The debugger is a program that allows the user to test and debug the object file. The
user can employ this program to perform the following functions.
Errors
Two possible kinds of errors can occur in assembly programs:
a. Programming errors: They are the familiar errors you can encounter in the course
of executing a program written in any language.
b. System errors: These are unique to assembly language that permit low-level
operations. A system error is one that corrupts or destroys the system under
which the program is running - In assembly language there is no supervising
40
Introduction to
interpreter or compiler to prevent a program from erasing itself or even from Assembly Language
erasing the computer operating system. Programming
• The assembler assigns line numbers to the statements in the source file
sequentially. If the assembler issues an error message; the message will contain a
reference to one of these line numbers.
• The second column from the left contains offsets. Each offset indicates the
address of an instruction or a datum as an offset from the base of its logical
segment, e.g., the statement at line 0010 produces machine language at offset
0000H of the CODE SEGMENT and the statement at line number 0002 produces
machine language at offset 0000H of the DATA SEGMENT.
• The third column in the annotation displays the machine language produce by
code instruction in the program.
Segment numbers: There is a good reason for not leaving the determination of
segment numbers up to the assembler. It allows programs written in 8086 assembly
language to be almost entirely relocatable. They can be loaded practically anywhere
in memory and run just as well. Program1 has to store the message “Have a nice
day$” somewhere in memory. It is located in the DATA SEGMENT. Since the
41
The Central
Processing Unit
characters are stored in ASCII, therefore it will occupy 15 bytes (please note each
Assembly Language
Programming blank is also a character) in the DATA SEGMENT.
Missing offset: The xxxx in the machine language for the instruction at line 0010 is
there because the assembler does not know the DATA segment location that will be
determined at loading time. The loader must supply that value.
Keyword: A keyword is a statement that defines the nature of that statement. If the
statement is a directive then the keyword will be the title of that directive; if the
statement is a data-allocation statement the keyword will be a data definition type.
Some examples of the keywords are: SEGMENT (directive), MOV (statement) etc.
Identifiers: An identifier is a name that you apply to an item in your program that
you expect to reference. The two types of identifiers are name and label.
1. Name refers to the address of a data item such as counter, arr etc.
2. Label refers to the address of our instruction, process or segment. For example
MAIN is the label for a process as:
MAIN PROC FAR
A20: BL,45 ; defines a label A20.
Identifier can use alphabet, digit or special character but it always starts with an
alphabet.
Parameters: A parameter extends and refines the meaning that the assembler
attributes to the keyword in a statement. The number of parameters is dependent on
the Statement.
2.4.2 Directives
Assembly languages support a number of statements. This enables you to control the
way in which a source program assembles and list. These statements, called
directives, act only when the assembly is in progress and generate no machine-
executable code. Let us discuss some common directives.
1. List: A list directive causes the assembler to produce an annotated listing on the
printer, the video screen, a disk drive or some combination of the three. An
annotated listing shows the text of the assembly language programs, numbers of
each statement in the program and the offset associated with each instruction and
each datum. The advantage of list directive is that it produces much more
informative output.
2. HEX: The HEX directive facilitates the coding of hexadecimal values in the
body of the program. That statement directs the assembler to treat tokens in the
42
Introduction to
source file that begins with a dollar sign as numeric constants in hexadecimal Assembly Language
notation. Programming
3. PROC Directive: The code segment contains the executable code for a
program, which consists of one or more procedures defined initially with the
PROC directive and ended with the ENDP directive.
5. ASSUME Directive: An .EXE program uses the SS register to address the base
of stack, DS to address the base of data segment, CS to address base of the code
segment and ES register to address the base of Extra segment. This directive tells
the assembler to correlate segment register with a segment name. For example,
CODE SEGMENT
The logical program segment is named code segment. When the linker links a
program it makes a note in the header section of the program’s executable file
describing the location of the code segment when the DOS invokes the loader to
load an executable file into memory, the loader reads that note. As it loads the
program into memory, the loader also makes notes to itself of exactly where in
memory it actually places each of the program’s other logical segments. As the
loader hands execution over to the program it has just loaded, it sets the CS
register to address the base of the segment identified by the linker as the code
segment. This renders every instruction in the code segment addressable in
segment relative terms in the form CS: xxxx.
The linker also assumes by default that the first instruction in the code segment
is intended to be the first instruction to be executed. That instruction will appear
in memory at an offset of 0000H from the base of the code segment, so the linker
passes that value on to the loader by leaving an another note in the header of the
program’s executable file.
43
The Central
Processing Unit
The loader sets the IP (Instruction Pointer) register to that value. This sets CS:IP
Assembly Language
Programming to the segment relative address of the first instruction in the program.
STACK SEGMENT
8086 Microprocessor supports the Word stack. The stack segment parameters
tell the assembler to alert the linker that this segment statement defines the
program stack area.
A program must have a stack area in that the computer is continuously carrying
on several background operations that are completely transparent, even to an
assembly language programmer, for example, a real time clock. Every 55
milliseconds the real time clock interrupts. Every 55 ms the CPU is interrupted.
The CPU records the state of its registers and then goes about updating the
system clock. When it finishes servicing the system clock, it has to restore the
registers and go back to doing whatever it was doing when the interruption
occurred. All such information gets recorded in the stack. If your program has
no stack and if the real time clock were to pulse while the CPU is running your
program, there would be no way for the CPU to find the way back to your
program when it was through updating the clock. 0400H byte is the default size
of allocation of stack. Please note if you have not specified the stack segment it
is automatically created.
DATA SEGMENT
It contains the data allocation statements for a program. This segment is very
useful as it shows the data organization.
DB Define byte 1
DW Define word 2
DD Define double word 4
DQ Define Quad word 8
DT Define 10 bytes 10
DUP Directive is used to duplicate the basic data definition to ‘n’ number of
times
ARRAY DB 10 DUP (0)
In the above statement ARRAY is the name of the data item, which is of byte
type (DB). This array contains 10 duplicate zero values; that is 10 zero values.
EQU directive is used to define a name to a constant
CONST EQU 20
44
Introduction to
Type of number used in data statements can be octal, binary, haxadecimal, Assembly Language
decimal and ASCII. The above statement defines a name CONST to a value 20. Programming
(b) DUP directive is used to indicate if a same memory location is used by two
different variables name.
(d) The maximum number of active segments at a time in 8086 can be four.
(e) ASSUME directive specifies the physical address for the data values of
instruction.
2.5.1 Interrupts
An interrupt causes interruption of an ongoing program. Some of the common
interrupts are: keyboard, printer, monitor, an error condition, trap etc.
45
The Central
Processing
AssemblyUnit
Language
Programming Hardware interrupts are generated when a peripheral Interrupt servicing program
requests for some service. A software interrupt causes a call to the operating system. It
usually is the input-output routine.
Let us discuss the software interrupts in more detail. A software interrupt is initiated
using the following statements:
INT number
In 8086, this interrupt instruction is processing using the interrupt vector table
(IVT). The IVT is located in the first 1K bytes of memory, and has a total of 256
entities, each of 4 bytes. An entry in the interrupt vector table is identified by the
number given in the interrupt instruction. The entry stores the address of the operating
system subroutine that is used to process the interrupt. This address may be different
for different machines. Figure 1 shows the processing of an interrupt.
Step 2: The CPU locates the interrupt servicing routine (ISR) whose address is stored
at IVT entry of the interrupt. For example, in the figure above the ISR of INT
10h is stored at location at a segment address F000h and an offset F065h.
Step 3: The CPU loads the CS register and the IP register, with this new address in
the IVT, and transfers the control to that address, just like a far CALL,
(discussed in the unit 4).
Step 4: IRET (interrupt return) causes the program to resume execution at the next
instruction in the calling program.
The advantage of this type of call is that it appears static to a programmer but flexible
to a system design engineer. For example, INT 00H is a special system level vector
that points to the “recovery from division by zero” subroutine. If new designer come
and want to move interrupt location in memory, it adjusts the entry in the IVT vector
of interrupt 00H to a new location. Thus from the system programmer point of view,
it is relatively easy to change the vectors under program control.
One of the most commonly used Interrupts for Input /Output is called DOS function
call. Let us discuss more about it in the next subsection:
47
The Central
Processing
AssemblyUnit
Language
Example of CR EQU ODH
Programming AH = 09H ; ASCII code of carriage return.
DATA SEGMENT
STRING DB ‘HELLO WORLD’, CR, ‘$’
DATA ENDS
CODE SEGMENT
:
MOV AX, DATA
MOV DS, AX
MOV AH, 09H
MOV DX, OFFSET STRING
; Store the offset of string in DX register.
INT 21H
AH = 0AH For input of string up to Look in the examples given.
255 characters. The string
is stored in a buffer.
AH = 4CH Return to DOS
48
Introduction to
; then type 9 Assembly Language
MOV AH, 08H Programming
INT 21H
MOV BL, AL ; If we have input 39 then, BL will first have character
; 3, we can convert it to 3 using previous logic that is 33 – 30 = 3.
SUB BL, ‘0’
MUL BL, AH ; To get 30 Multiply it by 10.
; Now BL Store 30
; Input another digit from keyboard
MOV AH, 08H
INT 21H;
MOV DL, AL ; Store AL in DL
SUB DL, ‘0’ ; (39 – 30) = 9.
; Now BL contains the value: 30 and DL has the value 9 add them and get the
; required numbers.
ADD BL, DL
; Now BL store 39. We have 2 digit value in BL.
Note: Boilerplate code is the code that is present more or less in the same form in
every assembly language program.
Strings Input
CODE SEGMENT
…
MOV AH, 0AH ; Move 04 to AH register
MOV DX, BUFF ; BUFF must be defined in data segment.
INT 21H
…..
CODE ENDS
DATA SEGMENT
BUFF DB 50 ; max length of string,
; including CR, 50 characters
DB ? ; actual length of string not known at present
DB 50 DUP(0) ; buffer having 0 values
DATA ENDS.
49
The Central
Processing Unit
Explanation
Assembly Language
Programming
The above DATA segment creates an input buffer BUFF of maximum 50 characters.
On input of data ‘JAIN’ followed by enter data would be stored as:
50 4 J A I N #
Here data from BL is moved to DL and then data display on monitor function is called
which displays the contents of DL register.
Here data in input buffer stored in data segment is going to be displayed on the
monitor.
A complete program:
Input a letter from keyboard and respond. “The letter you typed is ___”.
50
Introduction to
CODE SEGMENT Assembly Language
; set the DS register Programming
MOV AX, DATA
MOV DS, AX
; Read Keyboard
MOV AH, 08H
INT 21H
; Save input
MOV BL, AL
; Display first part of Message
MOV AH, 09H
MOV DX, OFFSET MESSAGE
INT 21 H
; Display character of BL register
MOV AH, 02H
MOV DL, BL
INT 21 H
; Exit to DOS
MOV AX, 4C00H
INT 21H
CODE ENDS
DATA SEGMENT
MESSAGE DB “The letter you typed is $”
DATA ENDS
END.
A COM program keeps its code, data, and stack segments within the same segment.
Since the offsets in a physical segment can be of 16 bits, therefore the size of COM
program is limited to 216 = 64K which includes code, data and stack. The following
program shows a COM program:
; Title add two numbers and store the result and carry in memory variables.
; name of the segment in this program is chosen to be CSEG
CSEG SEGMENT
ASSUME CS:CSEG, DS:CSEG, SS:CSEG
ORG 100h
START:MOV AX, CSEG ; Initialise data segment
MOV DS, AX ; register using AX
MOV AL, NUM1 ; Take the first number in AL
51
The Central
Processing Unit
ADD AL, NUM2 ; Add the 2nd number to it
Assembly Language
Programming MOV RESULT, AL ; Store the result in location RESULT
RCL AL, 01 ; Rotate carry into LSB
AND AL, 00000001B ; Mask out all but LSB
MOV CARRY, AL ; Store the carry result
MOV AX,4C00h
INT 21h
NUM1 DB 15h ; First number stored here
NUM2 DB 20h ; Second number stored here
RESULT DB ? ; Put sum here
CARRY DB ? ; Put any carry here
CSEG ENDS
END START
These programs are stored on a disk with an extension .com. A COM program
requires less space on disk rather than equivalent EXE program. At run-time the COM
program places the stack automatically at the end of the segment, so they use at least
one complete segment.
The load module of EXE program consists of up to 64K segments, although at the
most only four segments may be active at any time. The segments may be of variable
size, with maximum size being 64K.
52
Introduction to
RESULT DB ? ; Put sum here Assembly Language
CARRY DB ? ; Put any carry here Programming
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:MOV AX, DATA ; Initialise data segment
MOV DS, AX ; register using AX
MOV AL, NUM1 ; Bring the first number in AL
ADD AL, NUM2 ; Add the 2nd number to AL
MOV RESULT, AL ; Store the result
RCL AL, 01 ; Rotate carry into Least Significant Bit (LSB)
AND AL, 00000001B ; Mask out all but LSB
MOV CARRY, AL ; Store the carry
MOV AX, 4C00h ; Terminate to DOS
INT 21h
CODE ENDS
END START
1. Write an algorithm for your program closer to assembly language. For example,
the algorithm for preceding program would be:
get NUM1
add NUM2
put sum into memory at RESULT
position carry bit in LSB of byte
mask off upper seven bits
store the result in the CARRY location.
3. Study the instruction set carefully. This step helps in specifying the available
instructions and their format and constraints. For example, the segment registers
cannot be directly initialized by a memory variable. Instead we have to first move
the offset for segment into a register, and then move the contents of register to the
segment register.
You can exit to DOS, by using interrupt routine 21h, with function 4Ch, placed in AH
register.
53
The Central
Processing Unit
It is a nice practice to first code your program on paper, and use comments liberally.
Assembly Language
Programming This makes programming easier, and also helps you understand your program later.
Please note that the number of comments do not affect the size of the program.
After the program development, you may assemble it using an assembler and correct
it for errors, finally creating exe file for execution.
7. String input and output can be achieved using INT 21H with
function number 09h and 0Ah respectively.
16. EXE program contains a header module, which is used by DOS for
calculating segment addresses.
18. EXE programs are more easily relocatable than COM programs.
54
Introduction to
2.8 SUMMARY Assembly Language
Programming
55
The Central
Processing
AssemblyUnit
Language
Programming
2.9 SOLUTIONS/ ANSWERS
Check Your Progress 1
1. (a) It helps in better understanding of computer architecture and work in
machine language.
(b) Results in smaller machine level code, thus result in efficient execution of
programs.
(c) Flexibility of use as very few restrictions exist.
3. (a) False
(b) False
(c) True
(d) True
(e) False
(f) True
56
Assembly Language
UNIT 3 ASSEMBLY LANGUAGE Programming
(Part I)
PROGRAMMING (PART – I)
Structure Page No.
3.0 Introduction 57
3.1 Objectives 57
3.2 Simple Assembly Programs 57
3.2.1 Data Transfer
3.2.2 Simple Arithmetic Application
3.2.3 Application Using Shift Operations
3.2.4 Larger of the Two Numbers
3.3 Programming With Loops and Comparisons 63
3.3.1 Simple Program Loops
3.3.2 Find the Largest and the Smallest Array Values
3.3.3 Character Coded Data
3.3.4 Code Conversion
3.4 Programming for Arithmetic and String Operations 69
3.4.1 String Processing
3.4.2 Some More Arithmetic Problems
3.5 Summary 75
3.6 Solutions/ Answers 75
3.0 INTRODUCTION
After discussing a few essential directives, program developmental tools and simple
programs, let us discuss more about assembly language programs. In this unit, we will
start our discussions with simple assembly programs, which fulfil simple tasks such as
data transfer, arithmetic operations, and shift operations. A key example here will be
about finding the larger of two numbers. Thereafter, we will discuss more complex
programs showing how loops and various comparisons are used to implement tasks
like code conversion, coding characters, finding largest in array etc. Finally, we will
discuss more complex arithmetic and string operations. You must refer to further
readings for more discussions on these programming concepts.
3.1 OBJECTIVES
After going through this unit, you should be able to:
• write assembly programs with simple arithmetic logical and shift operations;
• implement loops;
• use comparisons for implementing various comparison functions;
• write simple assembly programs for code conversion; and
• write simple assembly programs for implementing arrays.
57
Assembly Language
Programming
; Program 1: This program shows the difference of MOV and XCHG instructions:
DATA SEGMENT
VAL DB 5678H ; initialize variable VAL
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
MAINP: MOV AX, 1234H ; AH=12 & AL=34
XCHG AH, AL ; AH=34 & AL=12
MOV AX, 1234H ; AH=12 & AL=34
MOV BX, VAL ; BH=56 & BL=78
XCHG AX, BX ; AX=5678 & BX=1234
XCHG AH, BL ; AH=34, AL=78, BH=12, & BL=56
MOV AX, 4C00H ; Halt using INT 21h
INT 21H
CODE ENDS
END MAINP
Discussion:
Just keep on changing values as desired in the program.
DATA SEGMENT
VALUE1 DB 0Ah ; Variables
VALUE2 DB 14h
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
MOV AX, DATA ; Initialise data segments
MOV DS, AX ; using AX
MOV AL, VALUE1 ; Load Value1 into AL
XCHG VALUE2,AL ; exchange AL with Value2.
MOV VALUE1,AL ; Store A1 in Value1
INT 21h ; Return to Operating system
CODE ENDS
END
Discussion:
The question is why cannot we simply use XCHG instruction with two memory
variables as operand? To answer the question let us look into some of constraints for
the MOV & XCHG instructions:
The MOV instruction has the following constraints and operands:
The statement MOV AL, VALUE1, copies the VALUE1 that is 0Ah in the AL
register:
58
Assembly Language
AX : 00 0A 0A (VALUE1) Programming
AH AL 14 (VALUE2) (Part I)
The instruction, XCHG AL, VALUE2 ; exchanges the value of AL with VALUE2
AX : 00 14 0A (VALUE1)
0A (VALUE2)
AX : 00 14 14 (VALUE1)
0A (VALUE2)
Other statements in the above program have already been discussed in the preceding
units.
; Input : Two memory variables stored in memory locations FIRST and SECOND
; REGISTERS ; Uses DS, CS, AX, BL
; PORTS ; None used
DATA SEGMENT
FIRST DB 90h ; FIRST number, 90h is a sample value
SECOND DB 78h ; SECOND number, 78h is a sample value
AVGE DB ? ; Store average here
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START: MOV AX, DATA ; Initialise data segment, i.e. set
MOV DS, AX ; Register DS to point to Data Segment
MOV AL, FIRST ; Get first number
ADD AL, SECOND ; Add second to it
MOV AH, 00h ; Clear all of AH register
ADC AH, 00h ; Put carry in LSB of AH
MOV BL, 02h ; Load divisor in BL register
DIV BL ; Divide AX by BL. Quotient in AL,
; and remainder in AH
MOV AVGE, AL ; Copy result to memory
CODE ENDS
END START
Discussion:
An add instruction cannot add two memory locations directly, so we moved a single
value in AL first and added the second value to it.
Please note, on adding the two values, there is a possibility of carry bit. (The values
here are being treated as unsigned binary numbers). Now the problem is how to put
59
Assembly Language
Programming
the carry bit into the AH register such that the AX(AH:AL) reflects the added value.
This is done using ADC instruction.
The ADC AH,00h instruction will add the immediate number 00h to the contents of
the carry flag and the contents of the AH register. The result will be left in the AH
register. Since we had cleared AH to all zeros, before the add, we really are adding
00h + 00h + CF. The result of all this is that the carry flag bit is put in the AH register,
which was desired by us.
Finally, to get the average, we divide the sum given in AX by 2. A more general
program would require positive and negative numbers. After the division, the 8-bit
quotient will be left in the AL register, which can then be copied into the memory
location named AVGE.
; Program 4: Convert the ASCII code to its BCD equivalent. This can be done by
simply replacing the bits in the upper four bits of the byte by four zeros. For example,
the ASCII ‘1’ is 32h = 0011 0010B. By making the upper four bits as 0 we get 0000
0010 which is 2 in BCD. The number obtained is called unpacked BCD number. The
upper four bits of this byte is zero. So the upper four bits can be used to store another
BCD digit. The byte thus obtained is called packed BCD number. For example, an
unpacked BCD number 59 is 00000101 00001001, that is, 05 09. The packed BCD
will be 0101 1001, that is 59.
The algorithm to convert two ASCII digits to packed BCD can be stated as:
Convert first ASCII digit to unpacked BCD.
Convert the second ASCII digit to unpacked BCD.
0101 0000
0000 1001
Pack 0101 1001 Using OR
;The assembly language program for the above can be written in the following
manner.
60
Assembly Language
; REGISTERS ; Uses CS, AL, BL, CL Programming
; PORTS ; None used (Part I)
CODE SEGMENT
ASSUME CS:CODE
START: MOV BL, '5' ; Load first ASCII digit in BL
MOV AL, '9' ; Load second ASCII digit in AL
AND BL, 0Fh ; Mask upper 4 bits of first digit
AND AL, 0Fh ; Mask upper 4 bits of second digit
MOV CL, 04h ; Load CL for 4 rotates
ROL BL, CL ; Rotate BL 4 bit positions
OR AL, BL ; Combine nibbles, result in AL contains 59
; as packed BCD
CODE ENDS
END START
Discussion:
8086 does not have any instruction to swap upper and lower four bits in a byte,
therefore we need to use the rotate instructions that too by 4 times. Out of the two
rotate instructions, ROL and RCL, we have chosen ROL, as it rotates the byte left by
one or more positions, on the other hand RCL moves the MSB into the carry flag and
brings the original carry flag into the LSB position, which is not what we want.
Let us now look at a program that uses RCL instructions. This will make the
difference between the instructions clear.
; Program 5: Add a byte number from one memory location to a byte from the next
memory location and put the sum in the third memory location. Also, save the carry
flag in the least significant bit of the fourth memory location.
; ALGORITHM:
; get NUM1
; add NUM2 in it
; put sum into memory location RESULT
; rotate carry in LSB of byte
; mask off upper seven bits of byte
; store the result in the CARRY location.
;
; PORTS : None used
; PROCEDURES : None used
; REGISTERS : Uses CS, DS, AX
;
DATA SEGMENT
NUM1 DB 25h ; First number
NUM2 DB 80h ; Second number
RESULT DB ? ; Put sum here
CARRY DB
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:MOV AX, DATA ; Initialise data segment
MOV DS, AX ; register using AX
MOV AL, NUM1 ; Load the first number in AL
ADD AL, NUM2 ; Add 2nd number in AL
61
Assembly Language
Programming
MOV RESULT, AL ; Store the result
RCL AL, 01 ; Rotate carry into LSB
AND AL, 00000001B ; Mask out all but LSB
MOV CARRY, AL ; Store the carry result
MOV AH, 4CH
INT 21H
CODE ENDS
END START
Discussion:
RCL instruction brings the carry into the least significant bit position of the AL
register. The AND instruction is used for masking higher order bits, of the carry, now
in AL.
In a similar manner we can also write applications using other shift instructions.
Let’s look at three examples that show how the flags are set when the numbers are
compared. In example 1 BL is less than 10, so the carry flag is set. In example 2, the
zero flag is set because both operands are equal. In example 3, the destination (BX) is
greater than the source, so both the zero and the carry flags are clear.
Example 1:
Example 2:
Example 3:
In the following section we will discuss an example that uses the flags set by CMP
instruction.
62
Assembly Language
1. In a MOV instruction, the immediate operand value for 8-bit destination cannot
exceed F0h.
4. A single instruction cannot swap the upper and lower four of a byte
register.
In the example above the control of the program will directly transfer to the label
THERE if the value stores in AX register is equal to that of the register BX. The same
example can be rewritten in the following manner, using different jumps.
Example 5:
CMP AX, BX ; compare instruction: sets flags
JNE FIX ; if not equal do addition
JMP THERE ; if equal skip next instruction
FIX: ADD AX, 02 ; add 02 to AX
63
Assembly Language
Programming
THERE: MOV CL, 07
The above code is not efficient, but suggest that there are many ways through which a
conditional jump can be implemented. Select the most optimum way.
Example 6:
CMP DX, 00 ; checks if DX is zero.
JE Label1 ; if yes, jump to Label1 i.e. if ZF=1
Example 7:
MOV AL, 10 ; moves 10 to AL
CMP AL, 20 ; checks if AL < 20 i.e. CF=1
JL Lab1 ; carry flag = 1 then jump to Lab1
LOOPING
; Program 6: Assume a constant inflation factor that is added to a series of prices
; stored in the memory. The program copies the new price over the old price. It is
; assumed that price data is available in BCD form.
; The algorithm:
;Repeat
; Read a price from the array
; Add inflation factor
; Adjust result to correct BCD
; Put result back in array
; Until all prices are inflated
Let us demonstrate the use of LOOP instruction, with the help of following program:
CODE SEGMENT
ASSUME : CS:CODE.
MAINP: MOV CX, 1AH ; 26 in decimal = 1A in hexadecimal Counter.
MOV DL, 41H ; Loading DL with ASCII hexadecimal of A.
NEXTC: MOV AH, 02H ; display result character in DL
INT 21H ; DOS interrupt
INC DL ; Increment DL for next char
LOOP NEXTC ; Repeat until CX=0.(loop automatically decrements
; CS and checks whether it is zero or not)
MOV AX, 4C00H ; Exit DOS
INT 21H ; DOS Call
CODE ENDS
END MAINP
DATA SEGMENT
XX DB ?
YY DB ?
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
MAINP: MOV AX, DATA ; initialize data
MOV DS, AX ; segment using AX
MOV CX, 03H ; set counter to 3.
NEXTP: MOV AH, 01H ; Waiting for user to enter a char.
INT 21H
MOV XX, AL ; store the 1st input character in XX
MOV AH, 01H ; waiting for user to enter second
INT 21H ; character.
MOV YY, AL ; store the character to YY
MOV BH, XX ; load first character in BH
MOV BL, YY ; load second character in BL
CMP BH, BL ; compare the characters
JNE NOT_EQUAL ;
65
Assembly Language
Programming
EQUAL: MOV AH, 02H ; if characters are equal then control
MOV DL, ‘Y’ ; will execute this block and
INT 21H ; display ‘Y’
JMP CONTINUE ; Jump to continue loop.
Discussion:
This program will be executed, at least 3 times.
; Program 9: Initialise the smallest and the largest variables as the first number in
; the array. They are then compared with the other array values one by one. If the
; value happens to be smaller than the assumed smallest number or larger than the
; assumed largest value, the smallest and the largest variables are changed with the
; new values respectively. Let us use register DI to point the current array value and
; LOOP instruction for looping.
DATA SEGMENT
ARRAY DW -1, 2000, -4000, 32767, 500,0
LARGE DW ?
SMALL DW ?
DATA ENDS
END.
CODE SEGMENT
MOV AX,DATA
MOV DS,AX ; Initialize DS
MOV DI, OFFSET ARRAY ; DI points to the array
MOV AX, [DI] ; AX contains the first element
MOV DX, AX ; initialize large in DX register
MOV BX, AX ; initialize small in BX register
MOV CX, 6 ; initialize loop counter
A1: MOV AX, [DI] ; get next array value
CMP AX, BX ; Is the new value smaller?
JGE A2 ; If greater then (not smaller) jump to
; A2, to check larger than large in DX
MOV BX, AX ; Otherwise it is smaller so move it to
; the smallest value (BX register)
JMP A3 ; as it is small, thus no need
; to compare it with the large so jump
; to A3 to continue or terminate loop.
66
Assembly Language
A2: CMP AX, DX ; [DI] = large Programming
JLE A3 ; if less than it implies not large so (Part I)
; jump to A3
; to continue or terminate
MOV DX, AX ; otherwise it is larger value, so move
; it to DX that store the large value
A3: ADD DI, 2 ; DI now points to next number
LOOP A1 ; repeat the loop until CX = 0
MOV LARGE, DX
MOV SMALL, BX ; move the large and small in the
; memory locations
MOV AX, 4C00h
INT 21h ; halt, return to DOS
CODE ENDS
Discussion:
Since the data is word type that is equal to 2 bytes and memory organisation is byte
wise, to point to next array value DI is incremented by 2.
As each digit is input, we would store its ASCII code in a memory byte. After the
first number was input the number would be stored as follows:
Each of these numbers will be input as equivalent ASCII digits and need to be
converted either to digit string to a 16-bit binary value that can be used for
computation or the ASCII digits themselves can be added which can be followed by
instruction that adjust the sum to binary. Let us use the conversion operation to
perform these calculations here.
Another important data format is packed decimal numbers (packed BCD). A packed
BCD contains two decimal digits per byte. Packed BCD format has the following
advantages:
• The BCD numbers allow accurate calculations for almost any number of
significant digits.
• Conversion of packed BCD numbers to ASCII (and vice versa) is relatively fast.
• An implicit decimal point may be used for keeping track of its position in a
separate variable.
The instructions DAA (decimal adjust after addition) and DAS (decimal adjust after
subtraction) are used for adjusting the result of an addition of subtraction operation on
67
Assembly Language
Programming
packed decimal numbers. However, no such instruction exists for multiplication and
division. For the cases of multiplication and division the number must be unpacked.
First, multiplied or divided and packed again. The instruction DAA and DAS has
already been explained in unit 1.
Program 10:
; This program converts an ASCII input to equivalent hex digit that it represents.
; Thus, valid ASCII digits are 0 to 9, A to F and the program assumes that the
; ASCII digit is read from a location in memory called ASCII. The hex result is
; left in the AL. Since the program converts only one digit number the AL is
; sufficient for the results. The result in AL is made FF if the character in ASCII
; is not the proper hex digit.
; ALGORITHM
; IF number <30h THEN error
; ELSE
; IF number <3Ah THEN Subtract 30h (it’s a number 0-9)
; ELSE (number is >39h)
; IF number <41h THEN error (number in range 3Ah-40h which is not a valid
; A-F character range)
; ELSE
; IF number <47h THEN Subtract 37h for letter A-F 41-46 (Please note
; that 41h – 37h = Ah)
; ELSE ERROR
;
; PORTS : None used
; PROCEDURES : None
; REGISTERS : Uses CS, DS, AX,
;
DATA SEGMENT
ASCII DB 39h ; Any experimental data
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START: MOV AX, DATA ; initialise data segment
MOV DS, AX ; Register using AX
MOV AL, ASCII ; Get the ASCII digits of the number
; start the conversion
CMP AL, 30h ; If the ASCII digit is below 30h then it is not
JB ERROR ; a proper Hex digit
CMP AL, 3Ah ; compare it to 3Ah
JB NUMBER ; If greater then possibly a letter between A-F
CMP AL, 41h ; This step will be done if equal to or above
; 3Ah
JB ERROR ; Between 3Ah and 40h is error
CMP AL, 46h
JA ERROR ; The ASCII is out of 0-9 and A-F range
SUB AL, 37h ; It’s a letter in the range A-F so convert
JMP CONVERTED
NUMBER: SUB AL, 30h ; it is a number in the range 0-9 so convert
JMP CONVERTED
68
Assembly Language
ERROR: MOV AL, 0FFh ; You can also display some message here Programming
CONVERTED: MOV AX, 4C00h (Part I)
INT 21h ; the hex result is in AL
CODE ENDS
END START
Discussions:
The above program demonstrates a single hex digit represented by an ASCII
character. The above programs can be extended to take more ASCII values and
convert them into a 16-bit binary number.
69
Assembly Language
Programming
The intermediate code in assembly language generated by a non-optimising compiler
for the above piece may look like:
MOV IND, 00 ; ind : = 0
L3: CMP IND, 08 ; ind < 9
JG L1 ; not so; skip
LEA AX, STR1 ; offset of str1 in AX register
MOV BX, IND ; it uses a register for indexing into
; the array
LEA CX, STR2 ; str2 in CX
MOV DL, BYTE PTR CX[BX]
CMP DL, BYTE PTR AX[BX] ; str1[ind] = str2[ind]
JNE L1 ; no, skip
MOV IND, BX
ADD IND, 01
L2: JMP L3 ; loop back
L1:
What we find in the above code: a large code that could have been improved further,
if the 8086 string instructions would have been used.
; Program 11: Matching two strings of same length stored in memory locations.
; REGISTERS : Uses CS, DS, ES, AX, DX, CX, SI, DI
DATA SEGMENT
PASSWORD DB 'FAILSAFE' ; source string
DESTSTR DB 'FEELSAFE' ; destination string
MESSAGE DB 'String are equal $'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, ES:DATA
MOV AX, DATA
MOV DS, AX ; Initialise data segment register
MOV ES, AX ; Initialise extra segment register
; as destination string is considered to be in extra segment. Please note that ES is also
; initialised to the same segment as of DS.
LEA SI, PASSWORD ; Load source pointer
LEA DI, DESTSTR ; Load destination pointer
MOV CX, 08 ; Load counter with string length
CLD ; Clear direction flag so that comparison is
; done in forward direction.
Discussion:
In the above program the instruction CMPSB compares the two strings, pointed by SI
in Data Segment and DI register in extra data segment. The strings are compared byte
by byte and then the pointers SI and DI are incremented to next byte. Please note the
last letter B in the instruction indicates a byte. If it is W, that is if instruction is
CMPSW, then comparison is done word by word and SI and DI are incremented by 2,
70
Assembly Language
that is to next word. The REPE prefix in front of the instruction tells the 8086 to Programming
decrement the CX register by one, and continue to execute the CMPSB instruction, (Part I)
until the counter (CX) becomes zero. Thus, the code size is substantially reduced.
Similarly, you can write efficient programs for moving one string to another, using
MOVS, and scanning a string for a character using SCAS.
A very useful application of assembly is to produce delay loops. Such loops are used
for waiting for some time prior to execution of next instruction.
But how to find the time for the delay? The rate at which the instructions are executed
is determined by the clock frequency. Each instruction takes a certain number of clock
cycles to execute. This, multiplied by the clock frequency of the microprocessor, gives
the actual time of execution of a instruction. For example, MOV instruction takes four
clock cycles. This instruction when run on a microprocessor with a 4Mhz clock takes
4/4, i.e. 1 microsecond. NOP is an instruction that is used to produce the delay,
without affecting the actual running of the program.
1
1 clock cycle =
5MHz
1
= Seconds
5 × 106
Thus, a 1-millisecond delay will require:
1 × 10−3
= clock cycles
1
6
5 × 10
= 5000 clock cycles.
The following program segment can be used to produce the delay, with the counter
value correctly initialised.
LOOP instruction takes 17 clock cycles when the condition is true and 5 clock cycles
otherwise. The condition will be true, ‘N’ number of times and false only once, when
the control comes out of the loop.
To calculate ‘N’:
Total clock cycles = clock cycles for MOV + N(2*NOP clock
cycles + 17) – 12 (when CX = 0)
71
Assembly Language
Programming
5000 = 4 + N(6 + 17) – 12
N = 5000/23 = 218 = 0DAh
Therefore, the counter, CX, should be initialized by 0DAh, in order to get the delay of
1 millisecond.
Use of array in assembly
Let us write a program to add two 5-byte numbers stored in an array. For example,
two numbers in hex can be:
20 11 01 10 FF
FF 40 30 20 10
1 1F 51 31 31 1F
Carry
Let us also assume that the numbers are represented as the lowest significant byte first
and put in memory in two arrays. The result is stored in the third array SUM. The
SUM also contains the carry out information, thus would be 1 byte longer than
number arrays.
DATA SEGMENT
NUM1 DB 0FFh, 10h ,01h ,11h ,20h
NUM2 DB 10h, 20h, 30h, 40h ,0FFh
SUM DB 6DUP(0)
DATA ENDS
LEN EQU 05h ; constant for length of the array
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START: MOV AX, DATA ; initialise data segment
MOV DS, AX ; using AX register
MOV SI, 00 ; load displacement of 1st number.
; SI is being used as index register
MOV CX, 0000 ; clear counter
MOV CL, LEN ; set up count to designed length
CLC ; clear carry. Ready for addition
AGAIN: MOV AL, NUM1[SI] ; get a byte from NUM1
ADC AL, NUM2[SI] ; add to byte from NUM2 with carry
72
Assembly Language
MOV SUM[SI], AL ; store in SUM array Programming
INC SI (Part I)
LOOP AGAIN ; continue until no more bytes
RCL AL, 01h ; move carry into bit 0 of AL
AND AL, 01h ; mask all but the 0th bit of AL
MOV SUM[SI], AL ; put carry into 6th byte
FINISH: MOV AX, 4C00h
INT 21h
CODE ENDS
END START
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START: MOV AX, DATA ; initialise data segment
MOV DS, AX ; using AX register
MOV AX, BCD ; get the BCD number AX = 4567
MOV BX, AX ; copy number into BX; BX = 4567
MOV AL, AH ; place for upper 2 digits in AX = 4545
MOV BH, BL ; place for lower 2 digits in BX = 6767
; split up numbers so that we have one digit
; in each register
MOV CL, 04 ; bit count for rotate
ROR AH, CL ; digit 1 (MSB) in lower four bits of AH.
; AX = 54 45
ROR BH, CL ; digit 3 in lower four bits of BH.
; BX = 76 67
AND AX, 0F0FH ; mask upper four bits of each digit.
; AX = 04 05
73
Assembly Language
Programming
AND BX, 0F0FH ; BX = 06 07
MOV CX, AX ; copy AX into CX so that can use AX for
; multiplication CX = 04 05
74
Assembly Language
3.5 SUMMARY Programming
(Part I)
In this unit, we have covered some basic aspects of assembly language programming.
We started with some elementary arithmetic problems, code conversion problems,
various types of loops and graduated on to do string processing and slightly complex
arithmetic. As part of good programming practice, we also noted some points that
should be kept in mind while coding. Some of them are:
In the next block, we take up more advanced assembly language programming, which
also includes accessing interrupts of the machine.
75
Assembly Language
Programming
2. Assuming that each array element is a word variable.
MOV CX, COUNT ; put the number of elements of the array in
; CX register
MOV AX, 0000h ; zero SI and AX
MOV SI, AX
; add the elements of array in AX again and again
AGAIN: ADD AX, ARRAY[SI] ; another way of handling array
ADD SI, 2 ; select the next element of the array
LOOP AGAIN ; add all the elements of the array. It will
terminate when CX becomes zero.
MOV TOTAL, AX ; store the results in TOTAL.
2. Direction flag if clear will cause REPE statement to perform in forward direction.
That is, in the given example the strings will be compared from first element to
last.
76
Assembly Language
UNIT 4 ASSEMBLY LANGUAGE Programming
(Part II)
PROGRAMMING (PART-II)
Structure Page No.
4.0 Introduction 77
4.1 Objectives 77
4.2 Use of Arrays in Assembly 77
4.3 Modular Programming 80
4.3.1 The stack
4.3.2 FAR and NEAR Procedures
4.3.3 Parameter Passing in Procedures
4.3.4 External Procedures
4.4 Interfacing Assembly Language Routines to High Level Language
Programs 93
4.4.1 Simple Interfacing
4.4.2 Interfacing Subroutines With Parameter Passing
4.5 Interrupts 97
4.6 Device Drivers in Assembly 99
4.7 Summary 101
4.8 Solutions/ Answers 102
4.0 INTRODUCTION
In the previous units, we have discussed the instruction set, addressing modes, and
other tools, which are needed to develop assembly language programs. We shall now
use this knowledge in developing more advanced tools. We have divided this unit
broadly into four sections. In the first section, we discuss the design of some simple
data structures using the basic data types. Once the programs become lengthier, it is
advisable to divide them into small modules, which can be easily written, tested and
debugged. This leads to the concept of modular programming, and that is the topic of
our second section in this unit. In the third section, we will discuss some techniques to
interface assembly language programs to high level languages. We have explained the
concepts using C and C ++ as they are two of the most popular high-level languages.
In the fourth section we have designed some tools necessary for interfacing the
microprocessor with external hardware modules.
4.1 OBJECTIVES
After going through this unit, you should be able to:
77
Assembly Language
Programming
An important application of array is the tables that are used to store related
information. For example, the names of all the students in the class, their CGPA, the
list of all the books in the library, or even the list of people residing in a particular area
can be stored in different tables. An important application of tables would be character
translation. It can be used for data encryption, or translation from one data type to
another. A critical factor for such kind of applications is the speed, which just happens
to be a strength of assembly language. The instruction that is used for such kind of
applications is XLAT.
Offset 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
Contents 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46
The content of this entry is now moved to the AL register, that is, 41h is moved to AL.
In other words, XLAT sets AL to 41h because this value is located at HEXA table
offset 0Ah. Please note that the 41h is the ASCII code for hex digit A. The following
sequence of instructions would accomplished this:
MOV AL, 0Ah ; index value
MOV BX, OFFSET HEXA ; offset of the table HEXA
XLAT
The above tasks can be done without XLAT instruction but it will require a long series
of instructions such as:
MOV AL, 0Ah ; index value
MOV BX, OFFSET HEXA ; offset of the table HEXA
PUSH BX ; save the offset
ADD BL, AL ; add index value to table
; HEXA offset
MOV AL, [BX] ; retrieve the entry
POP BX ; restore BX
Let us use the instruction XLAT for data encoding. When you want to transfer a
message through a telephone line, then such encoding may be a good way of
preventing other users from reading it. Let us show a sample program for encoding.
78
Assembly Language
PROGRAM 1: Programming
(Part II)
; A program for encoding ASCII Alpha numerics.
; ALGORITHM:
; create the code table
; read an input string character by character
; translate it using code table
; output the strings
DATA SEGMENT
CODETABLE DB 48 DUP (0) ; no translation of first
; 48 ASCII
DB ‘4590821367’ ; ASCII codes 48 –
; 57 ≡ (30h – 39h)
DB 7 DUP (0) ; no translation of
these 7 characters
DB ‘GVHZUSOBMIKPJCADLFTYEQNWXR’
DB 6 DUP (0) ; no translation
DB ‘gvhzusobmikpjcadlftyeqnwxr’
DB 133 DUP (0) ; no translation of remaining
; character
DATA ENDS
CODE SEGMENT
MOV AX, DATA
MOV DS, AX ; initialize DS
MOV BX, OFFSET CODETABLE ; point to lookup table
GETCHAR:
MOV AH, 06 ; console input no wait
MOV DL, 0FFh ; specify input request
INT 21h ; call DOS
JZ QUIT ; quit if no input is waiting
MOV DL, AL ; save character in DL
XLAT CODETABLE ; translate the character
CMP AL, 0 ; translatable?
JE PUTCHAR ; no : write it as is.
MOV DL, AL ; yes : move new character
; to DL
PUTCHAR:
MOV AH, 02 ; write DL to output
INT 21h
JMP GETCHAR ; get another character
QUIT: MOV AX, 4C00h
INT 21h
CODE ENDS
END
Discussion:
The program above will code the data. For example, a line from an input file will be
encoded:
The program above can be run using the following command line. If the program file
name is coding.asm
coding infile > outfile
79
Assembly Language
Programming
The infile is the input data file, and outfile is the output data file.
You can write more such applications using 8086 assembly tables.
Main Module
Module D Module E
80
Assembly Language
The advantages of modular programming are: Programming
(Part II)
1. Smaller, easier modules to manage
2. Code repetition may be avoided by reusing modules.
You can divide a program into subroutines or procedures. You need to CALL the
procedure whenever needed. A subroutine call transfers the control to subroutine
instructions and brings the control back to calling program.
In 8086 microprocessor a stack is created in the stack segment. The SS register stores
the offset of stack segment and SP register stores the top of the stack. A value is
pushed in to top of the stack or taken out (poped) from the top of the stack. The stack
segment can be initialized as follows:
STACK_ SEG SEGMENT STACK
DW 100 DUP (0)
TOS LABEL WORD
STACK_SEG ENDS
CODE SEGMENT
ASSUME CS:CODE, SS:STACK_SEG
MOV AX, STACK_SEG
MOV SS,AX ; initialise stack segment
LEA SP,TOP ; initialise stack pointer
CODE ENDS
END
The directive STACK_SEG SEGMENT STACK declares the logical segment for the
stack segment. DW 100 DUP(0) assigns actual size of the stack to 100 words. All
locations of this stack are initialized to zero. The stacks are identified by the stack top
and that is why the Label Top of Stack (TOS) has been selected. Please note that the
stack in 8086 is a WORD stack. Stack facilities involve the use of indirect addressing
through a special register, the stack pointer (SP). SP is automatically decremented as
items are put on the stack and incremented as they are retrieved. Putting something on
to stack is called a PUSH and taking it off is called a POP. The address of the last
element pushed on to the stack is known as the top of the stack (TOS).
81
Assembly Language
Programming
join them together in such a way that they can communicate with each other. This
extra code is sometimes referred to as linkage overhead.
A procedure call involves:
1. Unlike other branch instructions, a procedure call must save the address of the
next instruction so that the return will be able to branch back to the proper
place in the calling program.
2. The registers used by the procedures need to be stored before their contents
are changed and then restored just before the procedure is finished.
3. A procedure must have a means of communicating or sharing data with the
procedures that call it, that is parameter passing.
Calls, Returns, and Procedures definitions in 8086
The 8086 microprocessor supports CALL and RET instructions for procedure call.
The CALL instruction not only branches to the indicated address, but also pushes the
return address onto the stack. In addition, it also initialized IP with the address of the
procedure. The RET instructions simply pops the return address from the stack. 8086
supports two kinds of procedure call. These are FAR and NEAR calls.
The NEAR procedure call is also known as Intrasegment call as the called procedure
is in the same segment from which call has been made. Thus, only IP is stored as the
return address. The IP can be stored on the stack as:
.
.
Stack segment base (SS)
Low address
Please note the growth of stack is towards stack segment base. So stack becomes full
on an offset 0000h. Also for push operation we decrement SP by 2 as stack is a word
stack (word size in 8086 = 16 bits) while memory is byte organised memory.
FAR procedure call, also known as intersegment call, is a call made to separate code
segment. Thus, the control will be transferred outside the current segment. Therefore,
both CS and IP need to be stored as the return address. These values on the stack after
the calls look like:
When the 8086 executes the FAR call, it first stores the contents of the code segment
register followed by the contents of IP on to the stack. A RET from the NEAR
procedure. Pops the two bytes into IP. The RET from the FAR procedure pops four
bytes from the stack.
Procedure is defined within the source code by placing a directive of the form:
82
Assembly Language
<Procedure name> PROC <Attribute> Programming
(Part II)
A procedure is terminated using:
<Procedure name> ENDP
The <procedure name> is the identifier used for calling the procedure and the
<attribute> is either NEAR or FAR. A procedure can be defined in:
1. The same code segment as the statement that calls it.
2. A code segment that is different from the one containing the statement that calls
it, but in the same source module as the calling statement.
3. A different source module and segment from the calling statement.
In the first case the <attribute> code NEAR should be used as the procedure and code
are in the same segment. For the latter two cases the <attribute> must be FAR.
Let us describe an example of procedure call using NEAR procedure, which contains
a call to a procedure in the same segment.
PROGRAM 2:
Write a program that collects in data samples from a port at 1 ms interval. The upper 4
bits collected data same as mastered and stored in an array in successive locations.
; REGISTERS :Uses CS, SS, DS, AX, BX, CX, DX, SI, SP
; PROCEDURES : Uses WAIT
DATA_SEG SEGMENT
PRESSURE DW 100 DUP(0) ; Set up array of 100 words
NBR_OF_SAMPLES EQU 100
PRESSURE_PORT EQU 0FFF8h ; hypothetical input port
DATA_SEG ENDS
CODE_SEG SEGMENT
ASSUME CS:CODE_SEG, DS:DATA_SEG, SS:STACK_SEG
START: MOV AX, DATA_SEG ; Initialise data segment register
MOV DS, AX
MOV AX, STACK_SEG ; Initialise stack segment register
MOV SS, AX
MOV SP, OFFSET STACK – TOP ; initialise stack pointer top of
; stack
LEA SI, PRESSURE ; SI points to start of array
; PRESSURE
MOV BX, NBR_OF_SAMPLES ; Load BX with number
; of samples
MOV DX, PRESSURE_PORT ; Point DX at input port
; it can be any A/D converter or
; data port.
83
Assembly Language
Programming
INC SI ; Increment SI by two as dealing with
INC SI ; 16 bit words and not bytes
DEC BX ; Decrement sample counter
JNZ READ_NEXT ; Repeat till 100
; samples are collected
STOP: NOP
WAIT PROC NEAR
MOV CX, 2000H ; Load delay value
; into CX
HERE: LOOP HERE ; Loop until CX = 0
RET
WAIT ENDP
CODE_SEG ENDS
END
Discussion:
Please note that the CALL to the procedure as above does not indicate whether the
call is to a NEAR procedure or a FAR procedure. This distinction is made at the time
of defining the procedure.
The procedure above can also be made a FAR procedure by changing the definition of
the procedure as:
WAIT PROC FAR
.
.
WAIT ENDS
The procedure can now be defined in another segment if the need so be, in the same
assembly language file.
Let us discuss a program that uses a procedure for converting a BCD number to binary
number.
PROGRAM 3:
Conversion of BCD number to binary using a procedure.
Algorithm for conversion procedure:
Take a packed BCD digit and separate the two digits of BCD.
Multiply the upper digit by 10 (0Ah)
Add the lower digit to the result of multiplication
Program 3 (a): Use of registers for parameter passing: This program uses AH register
for passing the parameter.
84
Assembly Language
We are assuming that data is available in memory location. BCD and the result is Programming
stored in BIN (Part II)
DATA_SEG SEGMENT
BCD DB 25h ; storage for BCD value
BIN DB ? ; storage for binary value
DATA_SEG ENDS
STACK_SEG SEGMENT STACK
DW 200 DUP(0) ; stack of 200 words
TOP_STACK LABEL WORD
STACK_SEG ENDS
CODE_SEG SEGMENT
ASSUME CS:CODE_SEG, DS:DATA_SEG, SS:STACK_SEG
START: MOV AX, DATA_SEG ; Initialise data segment
MOV DS, AX ; Using AX register
MOV AX, STACK_SEG ; Initialise stack
MOV SS, AX ; Segment register. Why
; stack?
MOV SP, OFFSET TOP_STACK ; Initialise stack pointer
MOV AH, BCD
CALL BCD_BINARY ; Do the conversion
MOV BIN, AH ; Store the result in the
; memory
:
:
; Remaining program can be put here
;PROCEDURE : BCD_BINARY - Converts BCD numbers to binary.
;INPUT : AH with BCD value
;OUTPUT : AH with binary value
;DESTROYS : AX
85
Assembly Language
Programming
RET ; and return to calling program
BCD_BINARY ENDP
CODE_SEG ENDS
END START
Discussion:
The above program is not an optimum program, as it does not use registers minimally.
By now you should be able to understand this module. The program copies the BCD
number from the memory to the AH register. The AH register is used as it is in the
procedure. Thus, the contents of AH register are used in calling program as well as
procedure; or in other words have been passed from main to procedure. The result of
the subroutine is also passed back to AH register as returned value. Thus, the calling
program can find the result in AH register.
The advantage of using the registers for passing the parameters is the ease with which
they can be handled. The disadvantage, however, is the limit of parameters that can be
passed. For example, one cannot pass an array of 100 elements to a procedure using
registers.
CODE_SEG SEGMENT
ASSUME CS:CODE_SEG, DS:DATA_SEG, SS:STACK_SEG
START: MOV AX, DATA_SEG ; Initialize data
MOV DS, AX ; segment using AX register
MOV AX, STACK_SEG ; initialize stack
MOV SS, AX ; segment. Why stack?
MOV SP, OFFSET TOP_STACK ; initialize stack pointer
; Put pointer to BCD storage in SI and DI prior to procedure call.
MOV SI, OFFSET BCD ; SI now points to BCD_IN
MOV DI, OFFSET BIN ; DI points BIN_VAL
; (returned value)
CALL BCD_BINARY ; Call the conversion
86
Assembly Language
; procedure Programming
NOP ; Continue with program (Part II)
; here
Discussion:
In the program above, SI points to the BCD and the DI points to the BIN. The
instruction MOV AL,[SI] copies the byte pointed by SI to the AL register. Likewise,
MOV [DI], AL transfers the result back to memory location pointed by DI.
This scheme allows you to pass the procedure pointers to data anywhere in memory.
You can pass pointer to individual data element or a group of data elements like arrays
and strings. This approach is used for parameters passing to BIOS procedures.
87
Assembly Language
Programming
PROGRAM 3: Version 3
DATA_SEG SEGMENT
BCD DB 25h ; Storage for BCD test value
BIN DB ? ; Storage for binary value
DATA_SEG ENDS
CODE_SEG SEGMENT
ASSUME CS:CODE_SEG, DS:DATA_SEG, SS:STACK_SEG
START: MOV AX, DATA ; Initialise data segment
MOV DS, AX ; using AX register
MOV AX, STACK-SEG . ; initialise stack segment
MOV SS, AX ; using AX register
MOV SP, OFFSET TOP_STACK ; initialise stack pointer
MOV AL, BCD ; Move BCD value into AL
PUSH AX ; and push it onto word stack
CALL BCD_BINARY ; Do the conversion
POP AX ; Get the binary value
MOV BIN, AL ; and save it
NOP ; Continue with program
; PROCEDURE : BCD_BINARY Converts BCD numbers to binary.
; INPUT : None - BCD value assumed to be on stack before call
; OUTPUT : None - Binary value on top of stack after return
; DESTROYS : Nothing
Discussion:
The parameter is pushed on the stack before the procedure call. The procedure call
causes the current instruction pointer to be pushed on to the stack. In the procedure
flags, AX, BX, CX and BP registers are also pushed in that order. Thus, the stack
looks to be:
The instruction MOV BP, SP transfers the contents of the SP to the BP register. Now
BP is used to access any location in the stack, by adding appropriate offset to it. For
example, MOV AX, [BP + 12] instruction transfers the word beginning at the 12th
byte from the top of the stack to AX register. It does not change the contents of the BP
register or the top of the stack. It copies the pushed value of AH and AL at offset
008Eh into the AX register. This instruction is not equivalent to POP instruction.
Stacks are useful for writing procedures for multi-user system programs or recurvise
procedures. It is a good practice to make a stack diagram as above while using
procedure call through stacks. This helps in reducing errors in programming.
Segment Combinations
In 8086 assembler provides a means for combining the segments declared in different
modules. Some typical combine types are:
1. PUBLIC: This combine directive combines all the segments having the same
names and class (in different modules) as a single combined segment.
2. COMMON: If the segments in different object modules have the same name and
the COMMON combine type then they have the same beginning address. During
execution these segments overlay each other.
89
Assembly Language
Programming
3. STACK: If the segments in different object modules have the same name and the
combine type is STACK, then they become one segment, with the length the sum
of the lengths of individual segments.
These details will be more clear after you go through program 4 and further readings.
Identifiers
a) Access to External Identifiers: An external identifier is one that is referred in
one module but defined in another. You can declare an identifier to be external
by including it on as EXTRN in the modules in which it is to be referred. This
tells the assembler to leave the address of the variable unresolved. The linker
looks for the address of this variable in the module where it is defined to be
PUBLIC.
b) Public Identifiers: A public identifier is one that is defined within one module
of a program but potentially accessible by all of the other modules in that
program. You can declare an identifier to be public by including it on a
PUBLIC directive in the module in which it is defined.
Let us explain all the above with the help of the following example:
PROGRAM 4:
Write a procedure that divides a 32-bit number by a 16-bit number. The procedure
should be general, that is, it is defined in one module, and can be called from another
assembly module.
PUBLIC DIVISOR
90
Assembly Language
MOV SS, AX ; using AX register Programming
MOV SP, OFFSET TOP_STACK ; Initialize stack pointer (Part II)
MOV AX, DIVIDEND ; Load low word of
; dividend
MOV DX DIVIDEND + 2 ; Load high word of
; dividend
MOV CX, DIVISOR ; Load divisor
CALL SMART_DIV
; This procedure returns Quotient in the DX:AX pair and Remainder in CX register.
; Carry bit is set if result is invalid.
JNC SAVE_ALL ; IF carry = 0, result valid
JMP STOP ; ELSE carry set, don’t
; save result
ASSUME DS:MORE_DATA ; Change data segment
SAVE_ALL: PUSH DS ; Save old DS
MOV BX, MORE_DATA ; Load new data segment
MOV DS, BX ; register
MOV QUOTIENT, AX ; Store low word of
; quotient
MOV QUOTIENT + 2, DX ; Store high word of
; quotient
MOV REMAINDER, CX ; Store remainder
ASSUME DS:DATA_SEG
POP DS ; Restore initial DS
JMP ENDING
STOP: MOV DL, OFFSET MESSAGE
MOV AX, AH 09H
INT 21H
ENDING: NOP
CODE_SEG ENDS
END START
Discussion:
The linker appends all the segments having the same name and PUBLIC directive
with segment name into one segment. Their contents are pulled together into
consecutive memory locations.
The next statement to be noted is PUBLIC DIVISOR. It tells the assembler and the
linker that this variable can be legally accessed by other assembly modules. On the
other hand EXTRN SMART_DIV:FAR tells the assembler that this module will
access a label or a procedure of type FAR in some assembly module. Please also note
that the EXTRN definition is enclosed within the PROCEDURES SEGMENT
PUBLIC and PROCEDURES ENDS, to tell the assembler and linker that the
procedure SMART_DIV is located within the segment PROCEDURES and all such
PROCEDURES segments need to be combined in one. Let us now define the
PROCEDURE module:
; PROGRAM MODULE PROCEDURES
Discussion:
The procedure accesses the data item named DIVISOR, which is defined in the main,
therefore the statement EXTRN DIVISOR:WORD is necessary for informing
assembler that this data name is found in some other segment. The data type is defined
to be of word type. Please not that the DIVISOR is enclosed in the same segment
name as that of main that is DATA_SEG and the procedure is in a PUBLIC segment.
(b) A FAR call uses one word in the stack for storing the return address.
(c) While making a call to a procedure, the nature of procedure that is NEAR
or FAR must be specified.
(d) Parameter passing through register is not suitable when large numbers of
parameters are to be passed.
92
Assembly Language
Programming
(f) Parameter passing through stack is used whenever assembly language (Part II)
programs are interfaced with any high level language programs.
(i) A segment if declared PUBLIC informs the linker to append all the
segments with same name into one.
What are the main considerations for interfacing assembly to HLL? To answer that we
need to answer the following questions:
The answer to the above questions are dependent on the high level language (HLL).
Let us take C Language as the language for interfacing. The C Language is very
useful for writing user interface programs, but the code produced by a C compiler
does not execute fast enough for telecommunications or graphics applications.
Therefore, system programs are often written with a combination of C and assembly
language functions. The main user interface may be written in C and specialized high
speed functions written in assembly language.
93
Assembly Language
Programming
You must give a specific segment name to the code segment of your assembly
language subroutine. The name varies from compiler to compiler. Microsoft C,
and Turbo C require the code segment name to be_TEXT or a segment name
with suffix_TEXT. Also, it requires the segment name _DATA for the data
segment.
(iii) The arguments from C to the assembly language are passed through the stack.
For example, a function call in C:
function_name (arg1, arg2, ..., argn) ;
would push the value of each argument on the stack in the reverse order. That
is, the argument argn is pushed first and arg1 is pushed last on the stack. A
value or a pointer to a variable can also be passed on the stack. Since the stack
in 8086 is a word stack, therefore, values and pointers are stored as words on
stack or multiples of the word size in case the value exceeds 16 bits.
(iv) You should remember to save any special purpose registers (such as CS, DS,
SS, ES, BP, SI or DI) that may be modified by the assembly language routine. If
you fail to save them, then you may have undesirable/ unexplainable
consequences, when control is returned to the C program. However, there is no
need to save AX, BX, CX or DX registers as they are considered volatile.
(v) Please note the compatibility of data types:
char Byte (DB)
int Word (DW)
long Double Word (DD)
(vi) Returned value: The called assembly routine uses the followed registers for
returned values:
char AL
Near/ int AX
Far/ long DX : AX
Let us now look into some of the examples for interfacing.
94
Assembly Language
refer to Assembler manuals on details on models of C program. The models primarily Programming
differ in number of segments). (Part II)
PROGRAM 5:
Write an assembly function that hides the cursor. Call it from a C program.
. PUBLIC CUROFF
. MODEL small,C
. CODE
CUROFF PROC
MOV AH,3 ; get the current cursor position
XOR BX,BX ; empty BX register
INT 10h ; use int 10hto do above
OR CH,20h ; force to OFF condition
MOV AH,01 ; set the new cursor values
INT 10h
RET
CUROFF ENDP
END
For details on various interrupt functions used in this program refer to further
readings.
You can write another procedure in assembly language program to put the cursor on.
This can be done by replacing OR CH,20h instruction by AND CH,1Fh. You can call
this new function from C program to put the cursor on after the curoff.
Why the parameter is found in [BP+4]? Please look into the following stack for the
answer.
Parameter (0 or 1) BP + 4
Return Address BP + 2
Old value BP + 0
PROGRAM 7:
Write a subroutine in C that toggles the cursor. It takes one argument that toggles the
value between on (1) and off (0) using simplified directives:
PUBLIC CURSW
.MODEL small, C
.CODE
CURSW PROC switch:word
96
Assembly Language
switch off or switch on the cursor // Programming
: (Part II)
:
CURSW ENDP
END
In a similar manner the variables can be passed in C as pointers also. Values can be
returned to C either by changing the variable values in the C data segment or by
returning the value in the registers as given earlier.
4.5 INTERRUPTS
Interrupts are signals that cause the central processing unit to suspend the currently
executing program and transfer to a special program called an interrupt handler. The
interrupt handler determines the cause of the interrupt, services the interrupt, and
finally returns the control to the point of interrupt. Interrupts are caused by events
external or internal to the CPU that require immediate attention. Some external events
that cause interrupts are:
- Completion of an I/O process
- Detection of a hardware failure
How can we write an Interrupt Servicing Routine? The following are the basic but
rigid sequence of steps:
1. Save the system context (registers, flags etc. that will be modified by the ISR).
2. Disable the interrupts that may cause interference if allowed to occur during this
ISR's processing
3. Enable those interrupts that may still be allowed to occur during this ISR
processing.
4. Determine the cause of the interrupt.
5. Take the appropriate action for the interrupt such as – receive and store data
from the serial port, set a flag to indicate the completion of the disk sector
transfer, etc.
6. Restore the system context.
7. Re-enable any interrupt levels that were blocked during this ISR execution.
8. Resume the execution of the process that was interrupted on occurrence of the
interrupt.
MS-DOS provides you facilities that enable you to install well-behaved interrupt
handlers such that they will not interfere with the operating system function or other
interrupt handlers. These functions are:
Function Action
Int 21h function 25h Set interrupt vector
Int 21h function 35h Get interrupt vector
Int 21h function 31h Terminate and stay residents
97
Assembly Language
Programming
Here are a few rules that must be kept in mind while writing down your own Interrupt
Service Routines:
1. Use Int 21h, function 35h to get the required IVT entry from the IVT. Save this
entry, for later use.
2. Use Int 21h, function 25h to modify the IVT.
3. If your program is not going to stay resident, save the contents of the IVT, and
later restore them when your program exits.
4. If your program is going to stay resident, use one of the terminate and stay
resident functions, to reserve proper amount of memory for your handler.
Let us now write an interrupt routine to handle “division by zero”. This file can be
loaded like a COM file, but makes itself permanently resident, till the system is
running.
This ISR is divided into two major sections: the initialisation and the interrupt
handler. The initialisation procedure (INIT) is executed only once, when the program
is executed from the DOS level. INIT takes over the type zero interrupt vector, it also
prints a sign-on message, and then performs a terminate and “stay resident exit” to
MS-DOS. This special exit reserves the memory occupied by the program, so that it is
not overwritten by subsequent application programs. The interrupt handler (ZDIV)
receives control when a divide-by-zero interrupt occurs.
CR EQU ODH ; ASCII carriage return
LF EQU 0Ah ; ASCII line feed
BEEP EQU 07h ; ASCII beep code
BACKSP EQU 08h ; ASCII backspace code
1) The leader
2) The strategy procedure
99
Assembly Language
Programming
3) The interrupt procedure
The driver has either .sys or .exe extension and is originated at offset address 0000h.
The Header
The header contains information that allows DOS to identify the driver. It also
contains pointers that allow it to chain to other drivers loaded into the system.
The header section of a device driver is 18 bytes in length and contains pointers and
the name of the driver.
The first double word contains a –1 that informs DOS this is the last driver in the
chain. If additional drivers are added DOS inserts a chain address in this double word
as the segment and offset address. The chain address points to the next driver in the
chain. This allows additional drivers installed at any time.
The attribute word indicates the type of headers included for the driver and the type of
device the driver installs. It also indicates whether the driver control a character driver
or a block device.
The request header contains the length of the request header as its first byte. This is
necessary because the length of the request header varies from command to command.
The return status word communicate information back to DOS from the device driver.
The initialise driver command (00H) is always executed when DOS initialises the
device driver. The initialisation commands pass message to the video display
indicating that the driver is loaded into the system and returns to DOS the amount of
memory needed by the driver. You may only use DOS INT 21H functions 00H. You
can get more details on strategy from the further readings.
100
Assembly Language
(e) Hardware interrupts can be invoked with the help of INT function.
4.7 SUMMARY
In the above module, we studied some programming techniques, starting from arrays,
to interrupts.
Arrays can be of byte type or word type, but the addressing of the arrays is always
done with respect to bytes. For a word array, the address will be incremented by two
for the next access.
As the programs become larger and larger, it becomes necessary to divide them into
smaller modules called procedures. The procedures can be NEAR or FAR depending
upon where they are being defined and from where they are being called. The
parameters to the procedures can be passed through registers, or through memory or
stack. Passing parameters in registers is easier, but limits the total number of variables
that can be passed. In memory locations it is straight forward, but limits the use of the
procedure. Passing parameters through stack is most complex out of all, but is a
standard way to do it. Even when the assembly language programs are interfaced to
high level languages, the parameters are passed on stack.
Interrupt Service Routines are used to service the interrupts that could have arisen
because of some exceptional condition. The interrupt service routines can be
modified- by rewriting them, and overwriting their entry in the interrupt vector table.
101
Assembly Language
Programming
4.8 SOLUTIONS/ ANSWERS
Check Your Progress 1
1. We will give you an algorithm using XLAT instruction. Please code and run the
program yourself.
2.
SP Æ . .
SP Æ 00 00
50 50
30
00
50
Æ 55
Low address
Original after (a) after (b)
(c) The return for FIRST can occur only after return of SECOND. Therefore, the
stack will be back in original state.
2.
• Save the system context
• Block any interrupt, which may cause interference
• Enable allowable interrupts
• Determine the cause of interrupt
• Take appropriate action
• Restore system context
• Enable interrupts which were blocked in Step 2
102