Вы находитесь на странице: 1из 69

Advanced Microprocessors

Session XIX
Interrupts, DOS Services
09.11.2005
Dr. K.Rajanikanth
M.S.Ramaiah Institute of Technology, Bangalore
---------------------------------------------------------------Learning Objectives:

Understand interrupt system of 8086 and learn to write Interrupt Service Routines

Learn to use DOS Services

Introduction:

Normal program flow can be interrupted because of a variety of reasons.

When the interrupt occurs and is recognized, the values of the Flag register, CS
and IP registers are saved on the stack and the control is transferred from the
executing program to an associated Interrupt Service Routine (ISR). After
completing the ISR control returns to the interrupted program.

Thus, this mechanism is similar to yet different from Far Call. CALL is always an
instruction in the program. The mechanism of calling & returning from ISR is
some what different from normal CALL mechanism.

The concept of an interrupt vis--vis a far call is illustrated in the following


figure:

Interrupts
Interrupt Service
Routine (ISR)

CALL

Interrupt

Return from
Interrupt

RETURN

(ISR; Interrupt Service Procedure; Interrupt Handler All mean the same)
Interrupt can be because of:

An external interrupt signal at the pins NMI or INTR . These are called
Hardware interrupts (studied in a later session).

A Software interrupt instruction.

Internal causes resulting from execution of other instructions etc, like


Interrupt on Divide Error. (sometimes called exceptions)

Whatever be the source of interrupt:


An interrupt instruction has an associated numeric operand called interrupt type code;
a number in the range of 0 to 255 (00H to FFH). (Thus we can have a total of 256 type
codes)
The interrupt type code:

Is provided by external hardware like Interrupt Controller (in the case of


external interrupts).

Is specified as part of instruction in the case of Software Interrupts.

Is implicit in the case exceptions like Divide Error.

Whatever be the source of interrupt & what ever be the type code:

For an ISR, both CS and IP are specified.

To this extent, an ISR is like a far procedure.

CS and IP of an ISR together constitute the Interrupt Vector. Thus an


interrupt vector is 2 + 2 = 4 bytes long.

One interrupt vector is required for each interrupt type code. We have 256
possible interrupt type codes and thus 256 possible interrupt vectors.
Consequently, to specify all these interrupt vectors, we need 256 x 4 =
1024 bytes of memory.

Interrupt Vector Table: A table of 1024 bytes containing the 256 interrupt
vectors. Address range is 00000H (0:0) to 003FFH (0:03FFH). This is a memory
block of 1KB starting from 00000H

Interrupt vector corresponding to interrupt type code n starts at location 4 x n.

Example: Interrupt type code = 20H Corresponding interrupt vector starts at


20H x 4 = 80H. (In locations 80H, 81H, we have IP and in locations 82H, 83H,
we have CS)

Another Example: Interrupt type code = 00H Corresponding interrupt vector


starts at 00H x 4 = 00H. (00H, 01H: IP ; 02H, 03H: CS)

Interrupt type codes:

Some have predefined meaning;

Some are reserved for future use; and

Remaining interrupt type codes are free for user definitions.

This scheme is shown in the following Interrupt Vector Table:

Interrupt Vector Table


Address

Function

00H 03H

Divide Error

04H 07H

Single Step

08H 0BH

NMI

0CH 0FH

Breakpoint

10H 13H

Interrupt on Overflow

14H 7FH

Reserved

80H 3FFH

User-Defined

Type Codes

0
1
2
3
4
5 1F
20H - FFH

Interrupt Processing:
When an interrupt is to be processed:

Flags, CS and IP are pushed on to the stack.


(Note that no automatic pushing of Flags occurs with far Call!)

T and I flags are cleared (disabling Single Step and External Interrupts)

Control is transferred to the new CS : IP specified in the Interrupt Vector. (ISR


begins execution.)

Return from ISR:

To return from the ISR, the interrupt return (IRET) instruction is used.

Executing IRET pops IP, CS and Flags from the stack.

In particular, the status of T and I flags is restored.

Now, control returns to the interrupted program.

I Flag:

I flag is cleared disabling recognition of external interrupts. To enable them


within the ISR, programmer can enable them using STI (Set Interrupt Flag)
instruction.

CLI (Clear Interrupt Flag) instruction also clears the I flag disabling recognition
of interrupts from INTR pin.

The use of these instructions is studied in detail in a later session.

T Flag:

Setting the T flag enables Single Step. The, after the execution of every
instruction, an interrupt of type 1 is generated. This feature is quite useful for
debugging. (The ISR can display Register values & other useful information.)

Evidently, within the ISR, Single Step should not be in effect! So T is cleared. On
return from ISR, the value of T is restored.

This concept is illustrated in the following figure:

T Flag - 1
Program to be traced
(single-stepped):
T flag = 1

ISR for INT 1; Part of Debug


Monitor. T flag = 0

Software Interrupt Instructions (INT n):

These instructions appear as regular instructions in the program code.

INT 3 is 1 Byte long. (The only special case). Rest of INT n instructions are all
2 Byte long.

These instructions are commonly used to access system procedures. Example:


INT 21H to access DOS services.

A software interrupt instruction is more convenient than far call. It occupies less
memory as it needs only 1 or 2 bytes as against the 5 bytes required for a far Call.
Further, there is no need to remember the CS:IP values. These values are obtained
from the Interrupt Vector Table.

The software instruction format is as shown below:

opcode

type code

INT 3 Instruction:

Only INT n instruction that is 1 Byte long! Rest are 2 Byte long.

This is often used to effect a breakpoint in the program. The breakpoint service
routine can provide Register values and other information useful for debugging.
Any INT n can be used for implement a breakpoint. However, as INT 3 is only
1-byte long, it is comparatively easier to insert this instruction into the program.

INTO Instruction:

This instruction causes an Interrupt on Overflow. Thus if the O flag = 1, an


interrupt is generated as Interrupt Vector 4. And if the O flag = 0 , this instruction
results in no operation.

This instruction is placed in the program usually after arithmetic instructions that
may lead to overflow condition. (Recall that JO instruction also detects overflow
condition.)

Interrupts in PC:

Type codes 0 to 4 are used in the standard way.

Several interrupt type codes are dedicated to interrupts from hardware devices
like key board, mouse etc. Examples: 9 for Keyboard; 17H for Parallel Port.

Software interrupt instructions commonly used in Assembly Language Programs


are:

INT 21H : DOS Services

INT 27H : Terminate and Stay Resident (TSR)

INT 1AH : Clock Service etc.

DOS Services:

DOS provides a variety of services like Reading the Keyboard, Writing to


Display, Disk access facilities etc.

All these services are accessed in common via INT 21H

Before invoking INT 21H

We place a Function Code that indicates the service required in the


register AH.

Other relevant parameters if any are placed in appropriate registers

Examples:

Write to Standard Output Device


AH 02H; DL ASCII Char to be displayed

Display a Character String


AH 09H ; DS:DX Address of Char String
The Char String must be terminated with an ASCII $ (24H).

Complete list of functions may be found in the Text Book.

Before invoking a DOS function, user must Save & Restore registers if necessary.

Lower Level direct control of various I/O devices is possible via BIOS (Basic
Input Output System) function calls like INT 10H, INT 11H etc. (Not discussed in
this session)

This session discusses some simple examples of using INT 21H.

Reading Keyboard:

When a character typed on the key board is read, it may return the standard 7-Bit
ASCII code corresponding to the key typed. Additionally, Extended ASCII codes
are used to represent Function Keys, Key Combinations (Keys in combination
with Shift, Control, Alt keys). The full list of key codes used in a standard PC is
available in the Text Book.

In this session, we will consider 3 simple ways to read keyboard:


Read key with echo;
Read key without echo;
Read entire line with echo.

Read Key With Echo:

The code corresponding to the key typed is read. Further, the same character is
displayed on the screen also (echo). This routine responds to CNTL-C (That is,
when CNTL-C is typed, an immediate exit to DOS occurs)

This service can be realized by invoking INT 21H with AH 01H


On return, AL ASCII code of character typed.

If AL = 0, Extended ASCII code is indicated. In such a case, INT 21H must be


executed again to get the Extended ASCII code.

The Read Key Procedure may distinguish these cases suitably (for example, via
Carry flag). In the following routine, CARRY is cleared to indicate standard key
code and it is set to indicate extended key code.
KEY PROC FAR
MOV AH, 01H
INT

21H

OR

AL, AL

; Extended key code?

JNZ

KEY1

; No, return with carry = 0

INT

21H

; Extended code, read again

STC
KEY1: RET
KEY

ENDP

; and return with carry = 1

Read Key Without Echo:

The code corresponding to the key typed is read. However, the character is not
displayed on the screen also (no echo). Also, this routine does not respond to
CNTL-C (That is, typing CNTL-C does not cause an exit to DOS)

Invoke INT 21H with AH 06H & DL = FFH

On return, Z = 1 indicates that no char was typed.


Else, AL ASCII code of character typed. In this case, if AL = 0, Extended
ASCII code is indicated. Now, INT 21H must be executed again to get the
Extended ASCII code.

The Read Key Procedure may distinguish these cases suitably (for example, via
Carry flag). In the following routine, Z = 1 indicates that no key was typed. If Z =
0, the key code is returned in AL and the CARRY is cleared to indicate standard
key code and it is set to indicate extended key code.

KEYS

PROC FAR
MOV

AH, 06H

MOV

DL, 0FFH

INT

21H

JE

KEYS

; No key was typed.

OR

AL, AL

; Extended key code?

JNZ

KEYS1

; No, return with carry = 0

INT

21H

; Extended code, read again

STC
KEYS1: RET
KEYS

ENDP

; and return with carry = 1

Read Entire Line With Echo:

This service is used to read an entire line of characters. The characters read are
maintained in a buffer. Thus, this is Buffered Keyboard Input service.

Function Code: 0A H

Input Parameters:
DS:DX = Address of the Buffer
First byte of Buffer = Maximum Number of Characters to be read (up to 255)

Characters are read (displaying them as they are read) until the specified number
of characters are read OR until the Enter key (code is 0DH) is typed.

Upon return:

Second Byte of Buffer Actual number of characters read.

Third Byte of Buffer onwards The actual characters typed.

Hence, the Buffer Size must be 2 more than the number of characters to be read!
.MODEL

SMALL

.DATA
BUF1 DB

102 DUP (?)

; Allow a maximum of 100 characters

.CODE
.STARTUP
MOV BUF1, 100

; Char count allowed = 100

MOV DX, OFFSET BUF1


MOV AH, 0AH
INT
.EXIT
END

21H

Display One ASCII Character:

This service allows to display a single character on the screen.

Function Code: 02H or 06H As both of these are quite similar, we will illustrate
the use of Function Code 6 only.

DL ASCII Character to be displayed


.MODEL

TINY

.CODE
.STARTUP
MOV AH, 06H
MOV DL, 41H ; Display character A, ASCII code is 41H
INT

21H

.EXIT
END
Display Character String:

This service allows the display of a string of ASCII characters.

Function Code: 09H

DS:DX Address of the Character String

The Character String must be terminated with ASCII $ char (24H)

The character string could be of any length.

It could include control characters like Carriage Return (0DH), Line Feed (0AH)
etc. However, the character $ is used as the terminator and thus can not be part of
the string. ($ could be displayed as a single character using Function Code 06H as
explained above.)

MODEL SMALL
.DATA
MSG1

DB

0DH, 0AH, Advanced Microprocessors. $

.CODE
.STARTUP
MOV AH, 09H
MOV DX, OFFSET MSG1
INT

21H

.EXIT
END

Terminate Program:

EXIT directive used in all the examples described so far effects program
termination by using Function Code 4CH (Terminate Program)

This directive inserts the following 2 lines of code:


MOV AH, 4CH
INT

21H

Instead of .EXIT, the above 2 lines could be directly written by the programmer.

Set Interrupt Vector, Read Interrupt Vector:

These services allow the user to set / read the interrupt vector corresponding to a
type code. This is preferred to directly manipulating the Interrupt Vector Table.

AH 25H (Set Interrupt Vector)


AL Interrupt Vector Number
DS:DX Address of Interrupt Procedure

AH 35H (Read Interrupt Vector)


AL Interrupt Vector Number
On return, ES:BX Address stored at the vector.

Advanced Microprocessors
Session XX
Modular Programming
11.11.2005
Dr. K.Rajanikanth
M.S.Ramaiah Institute of Technology, Bangalore
---------------------------------------------------------------Learning Objectives:

Learn to use Modular Programming Techniques.

Understand and use Macros.


Modular Programming

Concepts:

Modular Programming is essential for conquering complexity inherent in the


development of large, industry-strength software systems.

The basic idea is the classical Divide & Conquer approach. Program is
composed from several smaller modules. Modules could be developed by separate
teams concurrently. The modules are only assembled producing .OBJ modules
(Object modules). Each module is produced from a separate Assembly Language
program.

The .OBJ modules so produced are combined using a LINK program.

The ML command of MASM typically used for smaller programs actually


consists of the two distinct steps of assembling to produce the object file and then
Linking the object module to produce the .EXE file.

Here, the two steps are separated.

This idea is illustrated in the following figure:

Concepts - 2
ASM File #1

Assembler

ASM File #2

Assembler

.OBJ file
.OBJ file

Linker

ASM File #n

Assembler

.EXE

.OBJ file

A further concept that is extremely useful is that of a Library of Object Modules.


Frequently used procedures could be assembled in to object modules and these object
modules are placed in a Library file that is linked into the application. Note that only the
required object modules are pulled from the Library to be linked in to the final
application. The concept of a Library is explored in detail later.
This idea is illustrated in the following figure:

Concepts - 3
ASM File

Assembler

ASM File

Assembler

.OBJ file
.OBJ file

Linker

.EXE

Library of Assembled Modules


(.OBJ files)

Assembler Features Required to Support Modular Programming:


To appreciate the features required to support Modular Programming, consider the
following development scenario:

In Module A , we defined
BUF1 DB 10 DUP (?)

In Module B , we wish to access BUF1, say as in


MOV DX, OFFSET BUF1

BUF1 is not defined in Module B. Thus, when assembling Module B, we will get
the assembly error of Undefined Symbol. Note that the symbol is actually
defined in Module A. But, the two modules are assembled independently!

Problem: How to make the BUF1, defined in Module A, accessible to Module B?

Solution:

Declare BUF1 as public in Module A


(Interpretation: Defined in this module, may be used in other modules.)

Declare BUF1 as external in Module B


(Interpretation: Used in this module, but defined in some other module.)

BUF1 becomes a global symbol.

Its use is resolved by a Linker program.

What happens if BUF1 is declared as external in one module; but Linker


does not find its definition in any of the modules being linked together?
This will be a Link Error, something like: Globally Unresolved
Symbol

Properly used, Public and External facilities allow modules to communicate with
each other, which is essential for Modular Programming.

PUBLIC and EXTRN Directives:


The following example illustrates the use of Public and External directives to achieve
communication among independently assembled modules.
PROG1.ASM, defines two symbols BUF1 and BUF2 and declares them as PUBLIC.
It also defines a Far Procedure called RDKEY and declares this also as PUBLIC.
Such a declaration allows these symbols to be accessed from other modules. Thus,
BUF1, BUF2 and RDKEY can be accessed from other modules.

File 1: PROG1.ASM
.MODEL SMALL
.DATA
PUBLIC

BUF1

PUBLIC

BUF2

BUF1 DB

10 DUP (?)

BUF2 DW

10 DUP (?)

.CODE
.STARTUP
PUBLIC
RDKEY PROC
MOV AH, 1
INT 21H
RDKEY

ENDP
END

RDKEY
FAR

In another program PROG2.ASM, we make use of the symbols BUF1, BUF2 and
RDKEY. We declare them as EXTRN. Such a declaration indicates that the
definitions for these symbols are not in this module; how ever this is not to be treated
as an error. These symbols are expected to be defined in other modules which will be
specified during LINK time.
Further, note that the type of the EXTRN data items must be declared for proper
assembly. Similarly, the FAR / NEAR nature of an EXTRN procedure also must be
declared for the Assembler to generate correct code.

File 2: PROG2.ASM
.MODEL

SMALL

.DATA
EXTRN

BUF1:BYTE

EXTRN

BUF2:WORD

.CODE
EXTRN

RDKEY:FAR

.STARTUP
MOV DX, OFFSET BUF1
MOV CX, 10
L1:

CALL RDKEY
STOSB
LOOP L1
MOV BUF2, AX
.EXIT
END

We now have 2 Files: PROG1.ASM and PROG2.ASM

These can be assembled and Linked by the following command


ML PROG1.ASM PROG2.ASM

Another way that more clearly illustrates the Modular Programming approach is
as follows :

Only assemble (not link) the two programs separately, getting the two
.OBJ files.

Run LINK utility and specify the two .OBJ files as inputs.

Experiment in the Laboratory.

LIBRARIES:

Frequently used procedures for a given application domain may be placed in a


Library File as .OBJ files.

The Library file can be specified at LINK time.

Only the required .OBJ files are extracted from the Library File and linked in to
the program.

Thus, Libraries provide a powerful reuse mechanism.

LIB Command:
The LIB command provides the following facilities:

Create a new Library file

Add .OBJ file to a Library file.

Delete .OBJ file from a Library file.

Replace an existing .OBJ file in the Library with another .OBJ file with the same
name (equivalent to Delete followed by Add)

The LIB command is used as follows:


LIB library file name

If the named Library file does not exist, the system prompts whether to create?
Type Y

It prompts for operation (operation could be specified on command line also).


The Operation can be:

+ (add) ; - (remove) ; -+ (replace)

Examples
Create a Library file called MYIO1.LIB and add the module PROG1 to the
library:
>LIB MYIO1.LIB
Copyright messages etc from the utility
Library file does not exist. Create? Y
Operations: +PROG1
List File: MYIO1
To the Library file called MYIO1.LIB add the module PROG2:
> LIB MYIO1.LIB
Copyright messages etc from the utility
Operations: +PROG2
>
To the Library file called MYIO1.LIB add the module PROG3:
>LIB MYIO1.LIB
Copyright messages etc from the utility
Operations: +PROG3
>

Alternatively, the 3 modules could be added to the Library file as shown below:
>LIB MYIO1.LIB
Copyright messages etc from the utility
Library file does not exist. Create? Y
Operations: PROG1 + PROG2 + PROG3
List File: MYIO1
>
From the Library file called MYIO1.LIB, remove the module PROG2:
> LIB MYIO1.LIB
Copyright messages etc from the utility
Operations: -PROG2
>

List file shows:

Sizes and names of the files in the Library

Public labels available in the Library

Once we create Library files, we can use them to link the required modules in to
the application program by specifying the Library files to the Linker. With ML or
with LINK, specify the Library files required in response to the prompt
Libraries [.lib]:

Library files have .lib as the default extension.

Macros
Macros provide several powerful mechanisms useful for the development of
generic programs.

A Macro is a group of instructions with a name.

When a macro is invoked, the associated set of instructions is inserted in place in


to the source, replacing the macro name. This macro expansion is done by a
Macro Preprocessor and it happens before assembly. Thus the actual Assembler
sees the expanded source!

We could consider the macro as shorthand for a piece of text; somewhat like a
new pseudo-code instruction.

Macros and Procedures:

Macros are similar to procedures in some respects, yet are quite different in many
other respects.

Procedure:

Only one copy exists in memory. Thus memory consumed is less.

Called when required;

Execution time overhead is present because of the call and return instructions.

Macro:

When a macro is invoked, the corresponding text is inserted in to the


source. Thus multiple copies exist in the memory leading to greater space
requirements.

However, there is no execution overhead because there are no additional call


and return instructions. The code is in-place.

These concepts are illustrated in the following figure:

CALL

Macro invoked

MACRO

Inserted in
place
RETURN

MACRO Definition:
A macro has a name. The body of the macro is defined between a pair of directives,
MACRO and ENDM. Two macros are defined in the example given below.
Examples of Macro Definitions:
; Definition of a Macro named PA2C
PA2C

MACRO
PUSH AX
PUSH BX
PUSH CX
ENDM

; Another Macro named POPA2C is defined here


POPA2C

MACRO
POP CX
POP BX
POP AX
ENDM

Examples of Macro usage:


The following examples illustrate the use of macros. We first show the source with
macro invocation and then show how the expanded source looks.
Program with macro invocations:
PA2C
MOV CX, DA1
MOV BX, DA2
ADD AX, BX
ADD AX, CX
MOV DA2, AX
POPA2C
When the Macro Preprocessor expands the macros in the above source, the expanded
source looks as shown below:
PUSH AX
PUSH BX
PUSH CX
MOV CX, DA1
MOV BX, DA2
ADD AX, BX
ADD AX, CX
MOV DA2, AX
POP CX
POP BX
POP AX

Note how the macro name is replaced by the associated set of instructions. Thus,
macro name does not appear in the expanded source code. In other words, the actual
Assembler does not see the macros. What gets assembled is the expanded source.
This process is illustrated in the following figure:

MACROS (continued)
.ASM file
with Macros

Macro
Preproc
essor

Assemble &
Link

.ASM file with


Macros Expanded

.EXE file

MACROS with Parameters:


Macros have several other interesting and powerful capabilities. One of these is the
definition and use of macros with parameters.
A macro can be defined with parameters. These are dummy parameters. When the
macro is invoked, we provide the actual parameters. During the macro expansion, the
dummy parameters are replaced by the corresponding actual parameters. The
association between the dummy and actual parameters is positional. Thus the first
actual parameter is associated with the first dummy parameter, the second actual
parameter with the second dummy one and so on.
This is illustrated in the following example where a Macro named COPY is defined
with two parameters called A and B.

Example:

COPY

MACRO

A,B

PUSH AX
MOV AX, B
MOV A, AX
POP AX
ENDM
The macro is invoked in the following code with actual parameters as VAR1 and
VAR2. Thus during the macro expansion, the parameter A is replaced by VAR1 and
the parameter B is replaced by VAR2.
COPY

VAR1, VAR2

The expanded code is:


PUSH AX
MOV AX, VAR2
MOV VAR1, AX
POP AX

Local Variables in a Macro:

Assume that a macro definition includes a label RD1 as in the following example:
READ MACRO
PUSH
RD1: MOV

A
DX
AH, 06

MOV

DL, 0FFH

INT

21H

JE

RD1

MOV

A, AL

POP

DX

ENDM

;; No key, try again

If READ macro is invoked more than once, as in


READ VAR1
READ VAR2
assembly error results!

The problem is that the label RD1 appears in the expansion of READ VAR1 as
well as in the expansion of READ VAR2. Hence, the label RD1 appears in both
the expansions. In other words, the Assembler sees the label RD1 at two different
places and this results in the Multiple Definition error!

SOLUTION: Define RD1 as a local variable in the macro.


READ MACRO

LOCAL

RD1

PUSH

DX

RD1: MOV

AH, 06

MOV

DL, 0FFH

INT

21H

JE

RD1

MOV

A, AL

POP

DX

;; No key, try again

ENDM

Now, in each invocation of READ, the label RD1 will be replaced,


automatically, with a unique label of the form ??xxxx ; where xxxx is a unique
number generated by Assembler. This eliminates the problem of multiple
definitions in the expanded source.

With the use of local variable as illustrated above,


READ

VAR1

gets expanded as:


PUSH
??0000: MOV

DX
AH, 06

MOV

DL, 0FFH

INT

21H

JE

??0000 ;; No key, try again

MOV

VAR1, AL

POP

DX

Subsequently, if we write
READ

VAR2

it gets expanded as:


PUSH
??0001: MOV

DX
AH, 06

MOV

DL, 0FFH

INT

21H

JE

??0001 ;; No key, try again

MOV

VAR2, AL

POP

DX

Note how each invocation of the READ macro gets expanded with a new and
unique label, generated automatically by the Assembler, in place of the local variable
RD1. Further, note that LOCAL directive must immediately follow the MACRO
directive. Another feature to note is that Comments in Macros are preceded by ;; (two
semicolons) , and not as usual by ; (a single semicolon).
File of Macros:

We can place all the required Macros in a file of its own and then include the file
into the source.

Example: Suppose the Macros are placed in D:\MYAPP\MYMAC.MAC


In the source file, we write
INCLUDE D:\MYAPP\MYMAC.MAC

Advanced Features:

Conditional Assembly

REPEAT , WHILE, and FOR statements in MACROS

Conditional Assembly:

A set of statements enclosed by IF and ENDIF are assembled if the condition


stated with IF is true; otherwise, the statements are not assembled; no code is
generated.

This is an Assembly time feature; not run-time behavior!

Allows development of generic programs. From such a generic program, we can


produce specific source programs for specific application contexts.

Example: Assume that our generic program has the following statements:
IF WIDT
WIDE

DB

72

DB

80

ELSE
WIDE
ENDIF
Now the assembly language program that is generated depends on the value of
WIDT. Assume the block is preceded by
WIDT EQU 1
Then the assembled code is:
WIDE DB

72

It is important to note that the Assembler sees a source file that has only the above
statement.

Another case:
WIDT EQU 0
IF WIDT
WIDE DB 72
ELSE
WIDE DB 80
ENDIF

What gets assembled is: WIDE DB

80

There are several other directives that can be used for Conditional Assembly as
listed below:
IF

If the expression is true

IFB

If the argument is blank

IFNB

If the argument is not blank

IFDEF

If the label has been defined

IFNDEF

If the label has not been defined

IFIDN

If argument 1 equals argument 2

IFDIF

If argument 1 does not equal argument 2

With each of the above constructs, the code that follows gets assembled only if the
stated condition is true.
REPEAT Statement:
This statement allows a block of code to be repeated the specified number of times.
This avoids repetitive typing and is much more elegant than Editor-level Copy-andPaste operation.
Example:
REPEAT 3
INT 21H
INC

DL

ENDM
The generated code would be 3 repetitions of the block of 2 statements enclosed
within REPEAT and ENDM as shown below:
INT 21H
INC DL
INT 21H
INC DL
INT 21H
INC DL

WHILE Statement:
This statement allows a block of code to be repeated while the condition specified
with the WHILE is true.
Example: Consider the following code
SQ LABEL BYTE
SEED = 1
RES = SEED * SEED
WHILE RES LE 9
DB

RES

SEED = SEED + 1
RES = SEED * SEED
ENDM
Note that SEED and the arithmetic statements involving SEED and RES are all
Assembly time actions. Apart from the initial label SQ, the only statement to actually
get repeated is DB RES.
The logic is follows: Initially the label SQ is generated. SEED is initialized to 1 and
RES is computed as 1 * 1 = 1. Now RES LE 9 is true as the value of RES is 1 which
is less than 9. So the code DB 1 is generated. The next statement within the scope of
WHILE, SEED = SEED + 1 is executed making SEED assume the value of 2. The
next statement within the scope of WHILE is RES = SEED * SEED. This is also
executed and RES assumes the value of 4. This completes one pass of execution of
the WHILE block. So, the condition associated with WHILE is again evaluated. This
is again TRUE as 4 is less than 9. So again DB 9 is generated. Reasoning as before,
we see that DB 9 is also generated. However, in the next pass SEED is 4 and RES is
16. So the condition RES LE 9 evaluates to FALSE and WHILE loop is exited!
Thus the generated code is:
SQ

DB

01

DB

04

DB

09

FOR Statement:
This is very similar to the FOR of languages like PERL. With the FOR statement, a
control variable and a list of values are specified. The control variable is successively
assigned values from the specified list and for each such value, the following block of
statements is repeated.
Example:
DISP MACRO CHR:VARARG
MOV AH, 2
FOR ARG, <CHR>
MOV DL, ARG
INT

21H

ENDM
ENDM
The outer Macro has one parameter which is specified as sequence of characters of
variable length. The inner FOR statement has two enclosed statements which will be
repeated for each value in the list <CHR>. Thus in the following illustration, DISP is
invoked with 3 characters as parameters. The two statements within FOR scope are
thus repeated 3 times with ARG successively assuming the 3 characters.
Thus, the statement
DISP V,T,U
gets expanded as
MOV

AH, 2

MOV

DL,V

INT

21H

MOV

DL, T

INT

21H

MOV

DL, U

INT

21H

Summary:

Modular programming techniques simplify the software development process by


exploiting the classical divide and conquer approach.

MACROS have very powerful features.

Used properly, they can reduce effort required to develop large and complex
programs. Further, Macros make it easy to develop Generic Programs which can
be easily adapted for specific applications.

Expertise with Modular programming techniques and Macros is essential for


developing industry-strength large scale software in Assembly Language.

Advanced Microprocessors
Session XXI
Data Conversion Routines
15.11.2005
Dr. K.Rajanikanth

----------------------------------------------------Learning Objectives:
Learn to develop Data Conversion Routines

Using Algorithmic Techniques and

Through Look Up Tables.

Introduction:

Often Data available in one format needs to be converted in to some other format.
Examples:

ASCII to Binary

Binary to ASCII

BCD to 7-Segment Code

Data Conversion may be based on

Algorithm

Look Up Table

Converting from Binary to ASCII:


In many contexts, for example, when displaying a number on the screen, we must
produce a sequence of ASCII characters representing the number to be displayed.
Thus the given number must be converted to a string of equivalent ASCII characters.

Example: Binary number: 0100 0011 = 43H = 67 D


To display this on the screen, we need to convert this binary number in to Two
ASCII characters, 6 and 7.
ASCII code for character 6 is 36H and
ASCII code for character 7 is 37H.
So, we need to produce 36H and 37H as output given 43H as input.

Another Example: Binary number: 0000 0010 0100 0011 = 0243H = 579 D
To display this on the screen, we need Three ASCII characters, 5, 7 and 9.
ASCII code for character 5 is 35H,
ASCII code for character 7 is 37H, and
ASCII code for character 9 is 39H
So, we need to produce 35H, 37H and 39H as output given 0243H as input

Binary to ASCII Algorithm:


Example: Binary number: 0000 0010 0100 0011 = 579 D
Divide 579 by 10 ; Quotient = 57 ; Remainder = 9 , Save 9

Divide 57 by 10;

Quotient = 5 ; Remainder = 7 , Save 7

Divide 5 by 10;

Quotient = 0 ; Remainder = 5 , Save 5

Quotient = 0 Conversion Complete.

Remainders saved in the order of 9, 7, and 5.

Retrieve remainders in the order of 5, 7, and 9.


(As the order of retrieval is the reverse of the order of producing these digits, the
most convenient technique is to Save & Retrieve the digits using Stack)

While retrieving, add 30H to convert the digit to ASCII code and then display it
(or print it, or save it)

Thus the algorithm is:


While the number is not equal to 0
Divide the number by 10;
Push the remainder digit on the stack;
Set number <- quotient
While stack not empty
Pop a digit from the stack
Add 30H to covert it to ASCII and display it
Return.

This algorithm is implemented in the following program:

Binary to ASCII Program:


; Input : 16-Bit Binary Number in AX
; Output: Equivalent ASCII displayed on screen
.MODEL TINY
.CODE
.STARTUP
MOV AX, 2A5H

; Test value

CALL B2A

; Binary to ASCII and Display

.EXIT
B2A

PROC

NEAR

PUSH DX
PUSH CX
PUSH BX

B2A1:

MOV

CX, 0

; Count of ASCII digits, Initialized to 0

MOV

BX, 10

; Divisor is 10

MOV DX, 0

; Dividend in DX, AX. So set DX = 0

DIV

; Divide by 10

BX

PUSH DX

; Save remainder digit on the stack

INC

CX

; Increment digit count

OR

AX, AX

; Conversion completed ? (Quotient, i.e AX = 0 ?)

JNZ

B2A1

; No, continue division

; Conversion is complete as quotient in AX = 0


; Count of remainder digits is in CX
B2A2: POP

DX

; Retrieve remainder in DL

ADD DL, 30H

; Convert to ASCII

MOV AH, 06H

; Console Display Function

INT

; DOS Service, display digit

21H

LOOP B2A2

; Repeat for all digits

; Clean up & Return. AX is destroyed


POP

BX

POP

CX

POP

DX

RET
B2A

ENDP
END

Notes:

DIV instruction requires the 32-bit dividend in the register pair DX and AX.
The number to be converted (and subsequently, the quotient) is in AX. So, DX
is cleared to 0 to set up the correct dividend.

As the digits are pushed on to the Stack, their count maintained in CX is


incremented. Thus the POPs occur in a loop controlled by CX. In the same
loop, as we POP each digit, 30H is added to produce the output in ASCII.

Another Method for Binary to ASCII Conversion:

When the input number is less than 100, an alternative, simpler method exists.

AAM (ASCII Adjust AX After Multiplication) instruction converts value in AX


in to 2-Digit Unpacked BCD and leaves it in AX.

Example: AX = 0027H (39 Decimal)


Execute AAM ; Now, AX = 0309H ; This is Unpacked BCD.

Now, add 3030H to AX to get 3339H ; This is Packed ASCII representation.

Separate the two bytes (unpack) to get the two ASCII characters representing the
given number (33H and 39H).

Works only when the number is less than 100 as the maximum unpacked BCD
that we can have in the AX register is 0909H only.

The following program is developed based on this idea.

; Input : Binary Number in AL, Assumed <100


; Output: Equivalent ASCII displayed on screen
.MODEL TINY
.CODE
.STARTUP
MOV

AL, 2AH

; Test value

CALL

B2A

; Binary to ASCII and Display

.EXIT
B2A

PROC

NEAR

PUSH DX
MOV AH, 0

; AX = Number

AAM

; AX = Unpacked BCD

ADD AX, 3030H

; Convert to ASCII

PUSH AX
; Now, unpack and display
MOV DL, AH

; First Digit

MOV AH, 06H

; Display Function

INT

21H

; Display first digit

POP

AX

; Retrieve value

MOV DL, AL

; Second Digit

MOV AH, 06H

; Display Function

INT

; Display second digit

21H

; Clean up & Return. AX is destroyed


POP

DX

RET
B2A

ENDP
END

Refinements:

Suppose the input is: AL = 7H. What is displayed is 07

Can we replace leading 0 with a blank so that the display looks better? Thus,
instead of 07, the display should be 7.

Yes. We need to check if the first digit is 0. If so, display 20H (blank);
else, display the digit.

We need to modify the previous program to incorporate this check for a leading 0.

Old Code for displaying first digit:


MOV DL, AH ; First Digit
MOV AH, 06H ; Display Function
INT

21H

; Display first digit

Revised Code for displaying first digit:


ADD AH, 20H

B2A1:

CMP AH, 20H

; First Digit = 0?

JZ

; Display blank (ASCII Code is 20H)

B2A1

ADD AH, 10H

; Add 10H more to get the correct ASCII Code for the digit

MOV DL , AH

; First Digit

MOV AH , 06H ; Display Function


INT

21H

; Display first digit

Incorporating this change, the program will be as shown below:

; Input : Binary Number in AL, Assumed <100


; Output: Equivalent ASCII displayed on screen
.MODEL TINY
.CODE
.STARTUP
MOV

AL, 2AH

; Test value

CALL

B2A

; Binary to ASCII and Display

.EXIT
B2A

PROC

NEAR

PUSH DX
MOV AH, 0

; AX = Number

AAM

; AX = Unpacked BCD

ADD AX, 3030H

; Convert to ASCII

PUSH AX
; Now, unpack and display
ADD AH, 20H
CMP AH, 20H

; First Digit = 0?

JZ

; YES. So, display a blank (ASCII Code is 20H)

B2A1

ADD AH, 10H

; No, we have already added 20H. Add 10H more


; to get the correct ASCII Code for the digit

B2A1: MOV DL, AH


MOV AH, 06H

; First Digit itself if not 0 , Or Blank (if 0)


; Display Function

INT

21H

; Display first digit

POP

AX

; Retrieve value

MOV DL, AL

; Second Digit

MOV AH, 06H

; Display Function

INT

; Display second digit

21H

; Clean up & Return. AX is destroyed


POP

DX

RET
B2A

ENDP
END

ASCII to Binary Algorithm:


In many contexts, for example, when reading a number from the key board, we get a
sequence of ASCII characters representing the number. This string of ASCII
characters must be converted to the equivalent number for further processing.
Example: Assume that ASCII character sequence 156 is the input.

3 characters, 1, 5, and 6; with codes as 31H, 35H, and 36H.

Converted Binary Value must be:


0000 0000 1001 1100 = 009CH = 156 (decimal)

Conversion Procedure:

Start with (Binary) Result = 0

First ASCII digit 31H; Subtract 30H to get corresponding BCD digit 01H.

Result = Result * 10 + Next BCD Digit


Result = 0 * 10 + 01 = 0000 0000 0000 0001

Next ASCII digit 35H; Subtract 30H to get corresponding BCD digit 05H.

Result = Result * 10 + Next BCD Digit


Result = 01 * 10 + 05 = 0000 0000 0000 1111

Next ASCII digit 36H; Subtract 30H to get corresponding BCD digit 06H.

Result = Result * 10 + Next BCD Digit


Result = 15 * 10 + 06 = 0000 0000 1001 1100

ASCII digits exhausted. So, conversion is completed.

Final Result = 0000 0000 1001 1100 = 009CH = 156 (decimal)

Based on the above ideas, the following program implements the ASCII to Binary
Conversion.

; ASCII to Binary Program


; ASCII characters representing a number are read from key board.
; The first non-digit character (any character other than 0 through 9) typed
; signals the end of the number entry
; Result returned in AX, which is then stored in memory location TEMP.
; Result assumed not to exceed 16 bits!
; Program can be modified to accept larger numbers by implementing
; 32- bit addition.
.MODEL
.DATA
TEMP

DW

.CODE
.STARTUP

SMALL

CALL RDNUM
MOV TEMP, AX
.EXIT
RDNUM PROC NEAR
PUSH BX
PUSH CX

RDN1:

MOV CX, 10

; Multiplier is 10

MOV BX, 0

; Result initialized to 0

MOV AH, 1

; Read Key with Echo

INT

21H

; Check the character. If less than 0 or greater than 9 Number entry is over
CMP AL, 0
JB

RDN2

CMP AL,9
JA

RDN2

; Is digit. Update Result


SUB

AL, 30H

; BCD Digit

PUSH AX
MOV AX, BX
MUL

CX

MOV

BX, AX

POP

AX

MOV

AH, 0

; AX = Current Digit

ADD

BX, AX

; Update Result

JMP

RDN1

; Repeat

; Result = Result * 10

; Non- digit. Clean Up and Return


RDN2:

MOV

AX, BX

POP

CX

POP

BX

RET
RDNUM

ENDP

; Result in AX

END
Notes:

The constant multiplier 10 is held in the register CX.

In the procedure, RDNUM, the result is accumulated in the register BX and at


the end, it is moved in to register AX. The result in AX is moved, in the
calling program, in to the memory location TEMP.

The BCD digit is in AL. AH is cleared to 0 so that the 16-bit value in AX


represents the correct value and thus can be added directly to the accumulating
result in BX. This part of the code must be changed to implement 32-bit
addition if larger results are to be supported.

Using Look Up Tables for Data Conversion:

Often, a look-up table simplifies data conversion.

XLAT can be used if table has up to 256 byte-entries

Value to be converted is used to index in to the table containing conversion


values.

As an example, we will demonstrate BCD to 7-Segment code conversion.

BCD to 7-Segment Code Conversion:


In many applications, we need to display BCD values on a 7-Segment display. The 7Segment display device, as the name suggests, has 7 segments which can be
independently controlled to be ON or OFF. Further, the device has a decimal point
also that can be switched ON or OFF. The 7 segments and the decimal point are
controlled by 8 bits, with one bit controlling one segment or the decimal point. The
bit value required to switch on a segment depends on whether the device is of a

Common Anode type or Common Cathode type. Here, we are assuming a


Common Anode type. Thus the segment will be ON if the corresponding
controlling bit is 1 and will be off if the bit is 0.
Based on the digit to be displayed, we must determine the segments that must be ON
and the ones that must be OFF. The bits controlling the segments that must be ON are
set to 1 and the bits controlling the segments that must be OFF are cleared to 0. The
resulting bit pattern determines the value of the 7-Segemnt code that must be output.
This display structure is shown in the following figure on the next page:

BCD to 7-Segment Code - 1


7 Segment display with active high (Logic 1) input
to light a segment.
Control Byte:

a
f

b
dp g

g
e

Bit = 1 Segment is on

d
dp

= 0 Segment is off

As an example of determining the display code corresponding to a given BCD digit,


the following figure shows the display of digit 3 and the determination of the
corresponding 7-Segment code:

BCD to 7-Segment Code - 2


Example: Display code for 3; No decimal point
Control Byte: a = 1; b = 1; c = 1; d = 1;
e = 0; f = 0 ; g = 1; dp = 0.

a
f

b
0

g
e

Display Code for 3 = 4F H

dp

Similarly, for other digits.

Based on the above logic, the following FAR Procedure returns the 7-Segment code
in the AL register, corresponding to the BCD digit provided as input parameter in the
AL register before calling the procedure.
; BCD to 7-Segment Code Program
; Input: AL = BCD Digit
; Output: AL = 7-Segment code.
BT7SEG

PROC FAR
PUSH BX
MOV BX, OFFSET TABLE
XLAT CS: TABLE
POP BX
RET

TABLE

DB

3FH ; 0

DB

06H ; 1

DB

5BH ; 2

DB

4FH ; 3

DB

66H ; 4

DB

6DH ; 5

BT7SEG

DB

7DH ; 6

DB

07H ; 7

DB

7FH ; 8

DB

6FH ; 9

ENDP

Notes:

XLAT instruction does not normally contain an operand. Here we are using the
operand (TABLE). It is a dummy operand! It is being used here only to specify
segment override. XLAT uses DS by default. Here the table is in CS. So segment
override is being specified.

More examples are discussed in the Text Book.

Advanced Microprocessors
Session XIV
Program Control Instructions - 1
21.10.2005
Dr. K.Rajanikanth
M.S.Ramaiah Institute of Technology, Bangalore
------------------------------------------Learning Objectives:
Learn to use conditional and unconditional jump instructions to control flow of program.

JUMP Group of Instructions


Introduction:

In almost any meaningful program, we need to alter the sequential flow of


execution.

Examples:
Instruction at reset CS:IP: At rest, 8086 begins execution at the address
FFFF:0000H (absolute address of FFFF0H). There are only 16 bytes from this
location to the end of the memory space (FFFFH)! It is unlikely that any

meaningful program can be written within this space. Thus the instruction at this
reset location is usually a long jump instruction that transfers control to some
suitable lower address based on the available memory.
A Sorting Program: A comparison-based sorting program would need to swap or
not swap two elements based on the outcome of the comparison of the two
elements. This would mean that we need an instruction to conditionally jump to
some other location in the program.
Any number of such examples can be given to illustrate the need for instructions
that alter the linear flow of control, either unconditionally or conditionally.

Unconditional and Conditional Jump Instructions allow such a control over the
execution flow.

Unconditional Jump:

No testing of any flags is involved in deciding whether a jump is to be executed


or not.

Control transfer occurs always.

This is illustrated in the following figure:

Unconditional Jump: Example


Before:

After:

CS=FFFF; IP=0000

CS=F000; IP=8000

FFFF0

F0
00
80
00
EA

Unconditionally
Jump here

F8000

01
00
B8

Target
Location

The instructions used for such unconditional jumps are discussed in detail later.

Conditional Jump:

Values of one or more flags are used in deciding whether a jump is to be executed
or not.

Thus, a jump may or may not occur depending on the values of such flag bits

This idea is illustrated in the following figure:

Conditional JUMP: Example


CMP AX,BX
JE
LAB1
MOV BX,1

LAB1: MOV BX,0

Test the Z flag


Target location
Test fails i.e Z=0 No jump;
Execution continues with the next
sequential instruction.
Control is transferred here only
if Z = 1. A conditional Jump.

The instructions used for such conditional jumps are discussed in detail later.

Unconditional Jump Instructions:

Unconditionally transfer control to an instruction located else where.

3 different instructions are available for such unconditional jumps.

All have similar behavior; but differ in where the target instruction is allowed to
be and consequently, the instruction lengths also differ. And that is the main
advantage.

The 3 forms are:


Short Jump: Target location must be within -128 to +127 bytes from the
address following the Jump instruction, i.e current IP. In this case, there is no
change in the CS value. Only IP is changed
Near Jump: Target location must be within -32768 to +32767 bytes from the
address following the Jump instruction, i.e current IP. In this case also, there
is no change in the CS value. Only IP is changed
Far Jump: Target location can be any where in the memory space. In this
case, CS as well as IP is changed.

Intra-Segment Jump Instructions:

Both Short Jump and Near Jump are called intra-segment jumps also because in
both the cases, there is no change in the CS value and only IP is changed. In other
words, the jump is to a location that is within the same code segment.

For these jumps, the target IP value is not specified as absolute value. Instead,
displacement (relative distance) from the current IP is specified.

Thus both are relative jumps. (Called Relative Program Memory Addressing in
earlier sessions)

Jump can be forward (to a higher address) or backwards (to a lower address).

So, displacement must be a signed number (can be positive or negative).

Short and Near Jumps differ in the way the displacement is specified.

Short Jump Instruction:

Specifies one byte displacement. It is sign-extended to 16 bits and added to


current IP to get new IP.

Displacement can be -128 to +127

This instruction occupies 2 bytes; the first byte specifies the opcode and the
second byte specifies the relative displacement as a signed 8-bit quantity. The
format is shown below:

Opcode
EB

Displacement
8-Bit Signed Value

A short jump instruction with positive relative displacement is illustrated in the


following figure:

Short Jump Instruction


1001C

Jmp Target

CS = 1000 H ; IP = 0002 H (Address


following the JMP instruction)
Displacement = 1A H = 0001 1010
Sign Extend = 001A H
New IP = 0002 + 001A = 001C H
Branch to 1000:001C

10002
10001
10000

1A
EB

(+ve displacement; Forward Jump)

A similar situation but with a negative relative displacement is illustrated in the


following figure:

Short Jump Instruction


10012
10011
10010

10005
10004
10003

F2
EB

CS = 1000 H ; IP = 0012 H (Address


following the JMP instruction)
Displacement = F2 H = 1111 0010
Sign Extend = FFF2 H
New IP = 0012 + FFF2 = 0004 H
(ignoring the carry out)
Branch to 1000:0004

Jmp Target

(-ve displacement; Backward Jump)

In a typical Assembly Language Program, we use labels for branch targets and
the Assembler will automatically compute the displacement.

We can force Short Jump to be assembled using the SHORT directive.

Anyway, most Assemblers choose the short form if possible (that is, if the
displacement is in the range of -128 to +127)

A program illustrating the Short Jump instruction is shown below:


XOR BX, BX
ST1: MOV AX, 1
ADD AX, BX
JMP SHORT NXT5 ; assume that the forward displacement <= 127
; some instructions
NXT5: MOV BX, AX
JMP ST1 ; assume that the backward displacement <= 128

Generally labels are used to denote branch targets.

However, it is also allowed to directly specify the target as $ + displacement


($ stands for current IP)

Example: JMP $ + 2 jumps over the next 2 memory locations following the JMP
instruction. Thus if the above instruction starts at 1000:0010, the after the jump,
control is transferred to the instruction at 1000: 0014

Near Jump Instruction:

This is quite similar to Short Jump except that the displacement is specified as
16 Bit signed integer rather than as 8-bit integer.

Target range is thus -32768 to +32767.

Target can be any where in the current code segment

Instruction is 3 Byte long. The first byte specifies the opcode and the next two
bytes specify the displacement. The format is shown in the following figure:

Opcode
E9

Displacement
Low Byte

High Byte

A near jump instruction with positive relative displacement is illustrated in the


following figure:

Near Jump Instruction


1201D Jmp Target

CS = 1000 H ; IP = 0003 H (Address


following the JMP instruction)
Displacement = 201A H
New IP = 0003 + 201A = 201D H
Branch to 1000:201D

10003
10002
10001
10000

(+ve displacement; Forward Jump)


20
1A
E9

A similar situation with a negative displacement is shown in the following figure:

Near Jump Instruction


10012
10011
10010

FF
F2
E9

CS = 1000 H ; IP = 0013 H (Address


following the JMP instruction)
Displacement = FFF2 H
New IP = 0013 + FFF2 = 0005 H
(ignoring the carry out)
Branch to 1000:0005

10006
10005
10004

(-ve displacement; Backward Jump)


Jmp Target

An Assembly Language Program illustrating Near Jump instruction is shown below:

XOR BX, BX
ST1: MOV AX, 1
ADD AX, BX
JMP NXT5
; Some instructions
NXT5: MOV BX, AX

The above program is quite similar to Short Jump Program listed earlier except that the
displacement to NXT5 is assumed to be greater than 127 and hence the instruction JMP
NXT5 is assembled as Near Jump.

Inter-Segment Jump Instruction:

FAR Jump is the only inter-segment jump instruction. It is called inter-segment


because the target location can be to any other code segment! Thus it is possible
that change occurs in the IP value as well as in the CS value.

Target is directly specified as new CS:IP.

Thus far jump can be to any where in the memory.

This instruction is 5 Byte long. The first byte specifies the opcode, the next 2
bytes specify the new IP value and the last 2 bytes specify the new CS value. The
format is shown in the following figure:

IP

Opcode

EA

Low
Byte

CS
Low
Byte

Low
Byte

An example illustrating the far jump is shown in the following figure:

Low
Byte

Inter-Segment Jump Instruction


20014
20013
20012

10
00
00

Before Far Jump:


CS = 2000 H ; IP = 0015 H (Address
following the JMP instruction)

20011
20010

04
EA

After the Far Jump:


New CS:IP = 1000:0004 H
Branch to 10004 H

10005
10004
10003

Jmp Target

In the ALP, we can use a label with FAR PTR directive.

Or, we can use a label that is defined as FAR LABEL.


(A label can be FAR only if it is external to the current code segment. So, it is
preceded by EXTRN directive.)

In such cases, the Linker will fill the CS and IP values at the link time.

An ALP showing the far jump is shown below:


EXTRN L1:FAR
ST1: MOV AX, 1

JMP FAR PTR ST1

JMP L1

Jump with Register Operands:

A 16-Bit register may be used as the operand for the jump instruction. (Indirect
Jump)

Contents of the register are transferred directly into IP (no concept of relative
displacement).

This option is available for Near Jump only.

Example: Assume BX = 0080H


After the execution of JMP BX instruction, the control is transferred to the
address 0080H in the current code segment.

Indirect Jump Using Index:

Uses [] form of addressing to directly access a table of jump addresses.

FAR PTR directive indicates a far jump ( jump table is assumed to contain
double words giving CS, IP values)

Otherwise a near jump is indicated. ( jump table is assumed to contain words


giving IP values)

This form is some times called Double Indirect Jump.

Example: JMP TABLE [SI]


Fetch the word, using indexed addressing, at the offset of TABLE [SI] from the
current code segment and copy that value into IP. (Near Jump)

Example: JMP FAR PTR [SI]


Fetch the double word, using indexed addressing, at the offset of [SI] from the
current code segment and copy the values into IP and CS.

Conditional Jump

Conditional jumps are always short jumps (relative displacement is -128 to +127).

Based on the values of one or more flags, jump to target address may occur or
execution may continue with the next sequential instruction.

Usually preceded by instructions like CMP, SUB, TEST, AND etc which affect
the flags.

Example:
CMP AX, BX
JZ

LAB1

MOV AX, BX
LAB1: MOV CX, AX

In the above program, equality of the operands is tested based on the Z flag.

Conditional jumps following general relative magnitude comparison are more


complicated. Consider the comparison of FEH with 1AH. Is FEH > 1AH ?
The answer depends on how we interpret the numbers!

Interpreted as Unsigned integers, 0FE H = 254 in decimal and 1A H = 170 in


decimal. Thus 0FE H > 1A H is true.

Interpreted as Signed integers using 2s Complement system, 0FE H = -2 in


Decimal and 1A H = 170 Decimal. Thus 0FE H > 1A H is false!

Thus, we have one set of conditional jump instructions that are to be used if the
numbers are to be interpreted as

Unsigned Integers and another set of

conditional jump instructions that are to be used if the numbers are to be


interpreted as Signed Integers.

After comparison of Unsigned integers:

Mnemonic

Condition

JA

Z=0 and C=0

Jump if above

JAE

C=0

Jump if above or equal

JB

C=1

Jump if below

JBE

Z=1 or C=1

Jump if below or equal

Operation

After comparison of Signed integers:

Mnemonic

Condition

Operation

JG

Z=0 and S=O

Jump if greater than

JGE

S=O

Jump if greater or equal

JL

S< >O

Jump if less than

JLE

Z=1 or S< >O

Jump if less or equal

(Both S and O Flags are required to test the condition when comparing signed numbers!)

After comparison of Signed or Unsigned integers:

Mnemonic

Condition

Operation

JE or JZ

Z=1

Jump if equal or Jump if Zero

JNE or JNZ

Z=0

Jump if not equal or Jump if not Zero

Alternative, less often used mnemonics also exist.

JA same as JNBE JG same as JNLE


JAE same as JNB JGE same as JNL
JB same as JNAE JL same as JNGE
JBE same as JNA JLE same as JNG

Other Conditional Jump Instructions:

Mnemonic

Condition

Operation

JC

C=1

Jump if carry set

JNC

C=0

Jump if no carry

JO

O=1

Jump if overflow

JNO

O=0

Jump if no overflow

JS

S=1

Jump if sign is set

JNS

S=0

Jump if no sign

Some more Conditional Jump Instructions:

Mnemonic

Condition

Operation

JP or JPE

P=1

Jump if parity set or Jump if parity is even

JNP or JPO

P=0

Jump if no parity or Jump if parity is odd

JCXZ

CX = 0

Jump if CX = 0

(Note that the last instruction, JCXZ is some what different from the rest in the sense
that it tests the contents of CX register rather than flags. This instruction, generally
used in loops, is illustrated in later sessions. Programs illustrating other conditional
jump instructions are also discussed in later sessions.)

Advanced Microprocessors
Session XV
Program Control Instructions - 2
25.10.2005
Dr. K.Rajanikanth

M.S.Ramaiah Institute of Technology, Bangalore


---------------------------------------------------------------Learning Objectives:

Learn to use LOOP instruction.

Understand machine control instructions (WAIT, ESC, NOP, HLT & LOCK
Prefix)

Learn to use Procedures

LOOP Instruction:

Program loops are quite common. Most of the counting loops have a typical
structure that is shown below:
MOV CX, 10H ; Initialize the count that determines the number of
; times the loop is to be executed.
Start1: Instructions constituting the loop body
DEC CX

; Decrement counter

JNZ Start1 ; Repeat if not over

If the pair of instructions that test whether the loop body is to be executed again or
not, that is the instructions, DEC CX and JNZ Start1, could be combined in to
one instruction, we would get more elegant and clearer program.

The LOOP instruction does so combine the above pair of instructions.

Thus the single instruction:


LOOP LAB1
is equivalent in effect to the two instructions:
DEC CX
JNZ LAB1

Conditional LOOP Instructions:

These instructions are similar to LOOP instruction except that equality (Z flag) is
also tested. This allows a loop to be controlled by a count as well as a comparison
test (like in the case of String instructions).

There are two such instructions.

LOOPE (Loop While Equal) or LOOPZ


Exit the loop if the condition is not equal or if CX decrements to 0.

LOOPNE (Loop While Not Equal) or LOOPNZ


Exit the loop if the condition is equal or if CX decrements to 0.

ESC Instruction

This instruction is related to 8087 Numeric Data Coprocessor. Details of 8087 are
discussed in later sessions. Briefly, 8087 provides support for floating point
operations and works as a coprocessor to 8086. It

Shares Pin bus with 8086.

Implements floating point arithmetic

and Has its own instruction set

The program has instructions for 8086 as well as 8087. How does 8087 know the
instruction is for itself? The solution to this problem is the ESC instruction.

ESC indicates that it is 8087 instruction. Opcode has 11011 as the higher-order 5
bits. Thus ESC is never used by itself.

Generated by Assembler automatically when 8087 mnemonic is used!


Consequently, ESC is never coded directly by the programmer.

WAIT Instruction

Monitors the TEST/ pin of 8086.

At the time of executing this instruction, if


TEST/ pin is LOW , there is no effect; execution simply continues with the next
instruction. However, if
TEST/ is HIGH , then 8086 waits in an idle state until TEST/ returns to LOW.

TEST/ is sampled during leading edge of CLK in each clock cycle during
waiting.

This instruction is generally used in conjunction with 8087.

8086 and 8087 can execute in parallel (concurrently)

WAIT instruction allows synchronization between the concurrently executing


8086 and 8087.

When 8086 needs the result from 8087, it executes the WAIT instruction.

TEST/ pin of 8086 is connected to the BUSY pin of 8087.

When 8087 is busy executing its instruction, it sets its BUSY pin = HIGH. Thus
TEST/ of 8086 will also be HIGH. This forces 8086 to wait for the completion
of 8087 activity.

When 8087 is not executing its instruction, its BUSY pin = LOW and thus the
TEST/ of 8086 will also be LOW. This allows 8086 to continue its execution.

In this manner, synchronization between 8086 and 8087 is achieved.

More on this topic in the session on 8087.

NOP Instruction

As the name implies, it is a no operation instruction!

Takes a short time to execute; otherwise no effect.

Used in early days to provide for manual code patches. Some NOP instructions
would be written every 100 bytes or so. When code was to be patched, the space
occupied by the NOP instructions was used. However, this is irrelevant in modern
times because the program development usually is based on Assemblers nad
manual coding is no more common.

Another use for this instruction is that it could be used for producing short time
delays if delay accuracy is not of concern.

HLT Instruction

As the name implies, it halts the program; the processor enters the HALT
state.

An interrupt or a hardware reset will force the 8086 out of the HALT state.

May be used when the program has to wait for an interrupt to occur; but rarely
used so in practice.

In the early days, this instruction was used in the trainer kits as the last instruction
of a user program. It is no more used in this fashion. In fact, presently it is rarely
used for any other purpose either!

LOCK Prefix

LOCK can be prefix of an instruction.

When such an instruction is executed, the LOCK/ pin of 8086 is activated (forced
LOW). Now, another bus master can not gain control of the bus until the end of
the bus lock. Thus the Lock prefixed instruction executes as an indivisible
instruction even if it has several memory cycles. (Without the LOCK prefix, the
bus could be taken over by another bus master after a memory cycle, even if the
current instruction is not completed!)

This feature is useful for implementing indivisible read modify-write kind of


operations that are necessary in multi-processor systems.

Example: LOCK: XCHG AL, SEM1


The instruction is executed without the possibility of another bus master
intervening.
Instruction shown above can be used in implementing semaphores in a multiprocessor system.

Procedures

Procedure or a subroutine or a function is a key concept for modular


programming, the essential way to conquer complexity. It is an application of the
general divide-and-conquer strategy. This idea is used in high-level language
programs as well as in assembly language programs.

A procedure is a reusable set of instructions that has a name.

Only one copy of the procedure is stored in the memory; and it can be called as
many times as needed.

As only one copy is stored, it saves memory; but has execution time overhead for
the call and return operations.

Macros to be studied later are faster but consume more space.

CALL transfers control to the procedure like with a jump; but unlike a jump,
procedure has a RETURN instruction which returns control to the instruction
following the CALL instruction! In order to implement such a return, the
necessary information is stored on a stack, before transferring control to the
procedure.

Further, nested procedures calls are possible. In other words, Procedure A can call
Procedure B which in turn calls Procedure C. After completing Procedure C,
control returns to Procedure B and after completing Procedure B, control returns
to Procedure A. Logically, such a nesting of calls can be to any level, though in
practice Assemblers impose implementation-dependent limits on the nesting
depth.

It is also possible for a Procedure to call itself (a recursive procedure). Of course,


to avoid infinite regress, the procedure would have an alternative that would not
involve recursion. Examples of recursive procedures are described in later
sessions.

These ideas are illustrated in the following figures:

Procedure
JMP

CALL

RETURN

Nesting of Procedures
CALL

CALL
CALL

RETURN

RETURN
RETURN

From the above figure we see that return addresses are known in one order and
are used for implementing return in exactly the reverse order. Thus a Stack
would be the most convenient data structure for storing return addresses

Coding Procedure and Procedure - Related Instructions:

Call can be to a procedure in the same code segment. In such a case, we specify
only IP as relative distance or indirectly as actual value. This is known as NEAR
CALL.

Call can be to a procedure in a different code segment. I such a case, we need to


specify both IP and CS (directly or indirectly). This is known as a FAR CALL

In ALP, procedure starts with PROC directive and ends with ENDP directive.

Each directive appears with the name of the procedure.

PROC directive is followed by the type of procedure: NEAR or FAR.

NEAR or FAR can be followed by USES statement.

USES statement allows specification of registers which are automatically pushed


on to the stack and popped from the stack within the procedure.

Near CALL Instruction:

Similar to Near Jump except that current IP is saved on the stack before
transferring control to the new IP with CS remaining the same.

Displacement is specified as 16 Bit signed integer. Target range is thus -32768


to +32767 and consequently, target can be any where in the current code segment

This Instruction is 3 Byte long and the format is as shown below:

opcode
E8

Displacement
Low Byte

High Byte

The operation of this instruction is illustrated in the following figure:

Near CALL Instruction


1201D Near Procedure

10003
10002
10001
10000

CS = 1000 H ; IP = 0003 H (Address


following the CALL instruction)
Displacement = 201A H
New IP = 0003 + 201A = 201D H
Push current IP (0003) on to stack &
Branch to 1000:201D

20
1A
E9

The saving of the return address is illustrated in the following figure:

Near CALL Instruction: Saving Return Address


AFFFF
AFFFE
AFFFD

10006
10005
10004

00
03

Saving IP:
Before CALL:
SS = A000 H ; SP = A000 H
IP = 0003

In ALP, NEAR indicates near procedure. The following program fragment illustrates the
coding and using of a near procedure:
ST1

PROC NEAR USES BX


MOV AX, 1
ADD AX, BX
RET

ST1

ENDP

CALL ST1

FAR CALL Instruction:

FAR CALL is like FAR JMP in the sense that it can call a procedure available
any where in the code space.

In this case, the target address is directly specified as new CS:IP.

Both current IP and CS are saved on the stack and then control is transferred to
the new CS:IP

The instruction is 5 Byte long. The first byte specifies the opcode, the next two
bytes specify the new IP value and the next two bytes specify the new CS value.
The format is shown below:

IP

opcode
E8

Low
Byte

CS
High
Byte

Low
Byte

High
Byte

The operation of the Far Call instruction is illustrated in the following figure:

FAR CALL Instruction


20014
20013
20012

10
00
00

Before Far CALL:


CS = 2000 H ; IP = 0015 H (Address
following the CALL instruction)

20011
20010

04
9A

After the Far CALL:


New CS:IP = 1000:0004 H
Save IP & CS on stack and

10005
10004
10003

Branch to 10004 H

Far Procedure

Example:
SUM1 PROC FAR

SUM1 ENDP
Now, a CALL to SUM1 is assembled as FAR CALL.

CALL with Register Operands:

As with JMP, 16-Bit register may be used as the operand for the CALL
instruction. (Indirect CALL)

Again, as with JMP, contents of the register are transferred directly into IP (no
concept of relative displacement).

This is always a Near CALL.

Example: Assume BX = 0080H. Now the execution of the instruction:


CALL BX
calls the procedure at 0080H in the current code segment (Near Call).

Indirect CALL Using Index:

Like the corresponding JMP instruction, this instruction uses [] form of


addressing to directly access a table of CALL addresses.

FAR PTR directive indicates a far CALL ( the table is assumed to contain double
words giving CS, IP values)

Otherwise a near CALL is indicated. ( the table is assumed to contain words


giving IP values)

This form is called Indirect Memory CALL also.

Example: CALL TABLE[SI]


Fetch the word, using indexed addressing, at the offset of TABLE[SI] from the
current code segment and CALL the near procedure at that address.

Example: CALL FAR PTR [SI]


Fetch the double word, using indexed addressing, at the offset of [SI] from the
current code segment and CALL the far procedure at that address.

Return from Procedure:

We use a RET instruction to return from the called procedure.

The control returns to the instruction following the CALL instruction in the
calling program. Corresponding to the two varieties of CALL instructions (near &
far), two forms of RET instructions (near & far) exist.

Near RET instruction pops a 16-Bit word from the stack and places it in the IP.

Far RET instruction pops two 16-Bit words from the stack and places them in IP
& CS.

In ALP, RET is written within the procedure, before the ENDP directive and the
Assembler will automatically select the proper RET instruction!

Another form: RET immediate value


Example: RET 6
In this case, after popping return address from the stack, the specified number (in
this case, 6) is added to SP, effectively removing some (in this case 3) words from
the stack! These words could have been pushed on to stack before calling. This is
the scheme followed by compilers. Examples are discussed in later sessions.

Вам также может понравиться