Module 3
Instruction Formats of 8086
The 8086 microprocessor supports a variety of instruction formats to accommodate different types
of operations and addressing modes. The primary formats are:
1. One-byte Instruction:
o These instructions are simple and require only one byte.
o Example: INC AX increments the AX register.
2. Register-to-Register:
o Instructions that operate between two registers.
o Example: MOV AX, BX moves the contents of BX to AX.
3. Register/Memory to/from Register:
o Instructions that involve transferring data between a register and a memory location
or another register.
o Example: MOV AX, [1234H] moves the content from memory location 1234H to AX.
4. Immediate to Register/Memory:
o Instructions where a constant value (immediate data) is moved to a register or
memory location.
o Example: MOV AX, 1234H loads the immediate value 1234H into AX.
5. Direct Addressing:
o Instructions that specify a memory address directly.
o Example: MOV AX, [1234H] moves the content from memory location 1234H to AX.
6. Register to Segment Register:
o Instructions that involve segment registers.
o Example: MOV DS, AX moves the content of AX to the DS segment register.
2. Instructions with Suitable Example
(i) LEA (Load Effective Address):
• Used to load the address of a variable into a register.
• Example: LEA AX, [BX+SI] loads the effective address formed by BX + SI into AX.
(ii) MOV (Move Data):
• Transfers data from one location to another.
• Example: MOV AX, BX moves the content of BX to AX.
(iii) ADD (Add):
• Adds the source operand to the destination operand and stores the result in the destination.
• Example: ADD AX, BX adds the contents of BX to AX.
(iv) INC (Increment):
• Increments the operand by one.
• Example: INC AX increments the AX register by 1.
(v) CMP (Compare):
• Compares two operands and sets the flags based on the result.
• Example: CMP AX, BX compares the contents of AX with BX.
(vi) XCHG (Exchange):
• Exchanges the contents of two operands.
• Example: XCHG AX, BX exchanges the contents of AX and BX.
3. Data Transfer Instructions in 8086 Microprocessor
Data transfer instructions are used to move data between registers, memory, and I/O ports. Some
key data transfer instructions are:
• MOV: Moves data from source to destination.
o Example: MOV AX, BX (moves data from BX to AX).
• PUSH: Pushes a word onto the stack.
o Example: PUSH AX (pushes AX onto the stack).
• POP: Pops a word off the stack.
o Example: POP AX (pops the top of the stack into AX).
• IN: Inputs a byte or word from a port to the accumulator.
o Example: IN AL, DX (inputs a byte from the port specified by DX into AL).
• OUT: Outputs a byte or word from the accumulator to a port.
o Example: OUT DX, AL (outputs a byte from AL to the port specified by DX).
• LEA: Loads the effective address of the operand into the specified register.
o Example: LEA BX, [SI+2] (loads the effective address of SI + 2 into BX).
4. Instructions Used for String Manipulation in 8086 Microprocessor
String manipulation instructions in the 8086 microprocessor allow operations on sequences of bytes
or words. The key categories are:
• MOVS (Move String): Transfers a byte or word from the source string to the destination
string.
o Example: MOVS B (moves a byte from DS to ES).
• LODS (Load String): Loads a byte or word from the source string into the accumulator.
o Example: LODS B (loads a byte from DS into AL).
• STOS (Store String): Stores a byte or word from the accumulator to the destination string.
o Example: STOSB (stores a byte from AL to ES).
• CMPS (Compare String): Compares two strings byte by byte or word by word.
o Example: CMPSB (compares byte at DS with byte at ES).
• SCAS (Scan String): Scans a string for a specified byte or word.
o Example: SCASB (scans ES for a byte in AL).
5. Loop Instructions, Shift and Rotate Instructions, Logical Instructions, and Branch Instructions
Loop Instructions:
• LOOP:
o Example: LOOP label decrements CX and jumps to label if CX is not zero.
• LOOPZ:
o Example: LOOPZ label decrements CX and jumps to label if CX is not zero and ZF is
set.
Shift and Rotate Instructions:
• SHL (Shift Left):
o Example: SHL AX, 1 shifts the bits in AX to the left by 1.
• ROR (Rotate Right):
o Example: ROR AX, 1 rotates the bits in AX to the right by 1.
Logical Instructions:
• AND:
o Example: AND AX, BX performs a bitwise AND between AX and BX.
• XOR:
o Example: XOR AX, BX performs a bitwise XOR between AX and BX.
Branch Instructions:
• JMP (Unconditional Jump):
o Example: JMP label jumps to the specified label.
• JE (Jump if Equal):
o Example: JE label jumps to label if the Zero Flag (ZF) is set.
Process of writing assembly Language program
Writing an assembly language program involves several steps:
1. Problem Analysis:
• Clearly define the problem and the desired output.
• Break down the problem into smaller, manageable steps.
2. Algorithm Development:
• Create a step-by-step procedure to solve the problem.
• This can be represented in flowchart or pseudocode form.
3. Assembly Language Coding:
• Translate the algorithm into assembly language instructions using appropriate mnemonics
and syntax.
• Use comments to explain the code's functionality.
• Consider data structures and memory allocation.
4. Assembler:
• Use an assembler to translate the assembly code into machine code (object code).
• The assembler checks for syntax errors and generates error messages if necessary.
5. Linker:
• Combine the object code with other modules (if any) and libraries to create an executable
file.
• Resolves external references and creates the final program.
6. Debugging:
• Test the program with different input values to identify and correct errors.
• Use debugging tools to step through the code and examine register values, memory
contents, and flags.
Example: Adding two numbers
DATA SEGMENT
NUM1 DW 1234h
NUM2 DW 5678h
RESULT DW ?
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX
MOV AX, NUM1
ADD AX, NUM2
MOV RESULT, AX
MOV AH, 4Ch
INT 21h
CODE ENDS
END START
Difference between jump and loop instructions
Jump Instructions
• Unconditionally transfer program control to a specified address.
• No built-in counter or condition checking mechanism.
• Used for implementing conditional branching and unconditional jumps.
Loop Instructions
• Execute a block of code repeatedly a specified number of times.
• Involve a counter that is decremented after each iteration.
• Automatically check the counter value and decide whether to continue or exit the loop.
Example:
To implement a loop that iterates 10 times:
Using Jump:
MOV CX, 10
LOOP_START:
; code to be repeated
DEC CX
JNZ LOOP_START
Using Loop:
MOV CX, 10
LOOP_START:
; code to be repeated
LOOP LOOP_START
Explain following Assembler Directive in 8086
(i) ASSUME:
• Tells the assembler which segment registers to use for different segments.
• Example: ASSUME CS:code, DS:data
(ii) EQU:
• Defines a constant without allocating storage.
• Example: MAX EQU 100 defines MAX as 100.
(iii) DW (Define Word):
• Allocates and initializes memory for word-sized variables.
• Example: num DW 1234H allocates a word and initializes it to 1234H.
(iv) DD (Define Double Word):
• Allocates and initializes memory for double word-sized variables.
• Example: dword DD 12345678H allocates a double word and initializes it to 12345678H.
(v) ENDS:
• Marks the end of a segment.
• Example: data ENDS indicates the end of the data segment.
Various Flags in 8086
1. Carry Flag (CF):
o Set if there is a carry out from the most significant bit during arithmetic operations.
2. Parity Flag (PF):
o Set if the number of set bits in the result is even.
3. Auxiliary Carry Flag (AF):
o Set if there is a carry from the lower nibble to the upper nibble in BCD operations.
4. Zero Flag (ZF):
o Set if the result of an operation is zero.
5. Sign Flag (SF):
o Set if the result of an operation is negative.
6. Overflow Flag (OF):
o Set if there is a signed overflow in arithmetic operations.
7. Direction Flag (DF):
o Determines the direction of string operations. If set, string operations auto-
decrement; otherwise, they auto-increment.
8. Interrupt Flag (IF):
o Controls the handling of interrupts. If set, interrupts are enabled; if clear, interrupts
are disabled.
Explain the Following Directives: SEGMENT, ENDS, ASSUME, ORG, EQU, and END
1. SEGMENT: Defines the beginning of a segment.
o Example: data SEGMENT
2. ENDS: Marks the end of a segment.
o Example: data ENDS
3. ASSUME: Associates a segment register with a segment.
o Example: ASSUME CS:code, DS:data
4. ORG: Sets the origin (starting address) for the code or data.
o Example: ORG 100h
5. EQU: Defines a constant value.
o Example: MAX EQU 10
6. END: Marks the end of the source code file.
o Example: END _start
DAA, DAS, AAA, and AAS Instructions
These instructions are primarily used for adjusting results of arithmetic operations to accommodate
specific data formats, particularly BCD (Binary Coded Decimal) and ASCII.
DAA (Decimal Adjust Accumulator After Addition)
• Used after an addition operation to correct the result in the accumulator if it contains
unpacked BCD digits.
• Adjusts the accumulator content to valid unpacked BCD digits.
• Sets the auxiliary carry flag (AF) if a carry occurs from bit 3 to bit 4 of a digit.
• Sets the carry flag (CF) if a carry occurs from bit 7 of the accumulator.
DAS (Decimal Adjust Accumulator After Subtraction)
• Used after a subtraction operation to correct the result in the accumulator if it contains
unpacked BCD digits.
• Adjusts the accumulator content to valid unpacked BCD digits.
• Clears the auxiliary carry flag (AF) if a borrow occurs from bit 4 of a digit.
• Sets the carry flag (CF) if a borrow occurs from bit 7 of the accumulator.
AAA (ASCII Adjust Accumulator After Addition)
• Used after an addition of two ASCII digits to correct the result in the accumulator.
• Converts the result from binary to unpacked BCD.
• Sets the auxiliary carry flag (AF) if a carry occurs from bit 3 to bit 4.
• Sets the carry flag (CF) if the result is greater than or equal to 16.
AAS (ASCII Adjust Accumulator After Subtraction)
• Used after a subtraction of two ASCII digits to correct the result in the accumulator.
• Converts the result from binary to unpacked BCD.
• Clears the auxiliary carry flag (AF) if a borrow occurs from bit 4.
• Sets the carry flag (CF) if the result is negative.
Macros in 8086
A macro is a user-defined block of assembly language instructions that can be reused multiple times
within a program. It's a way to define a custom instruction or a sequence of instructions that can be
given a name and used later
Features of Macros in 8086
• Code Reusability: Macros promote code reusability, reducing redundancy in the code.
• Modularity: They help in breaking down complex tasks into smaller, manageable units.
• Flexibility: Macros can accept parameters, allowing for customization.
• Efficiency: While not as efficient as procedures in terms of memory usage, macros can be
faster in execution as there's no function call overhead.
• Definition: Macros are defined using the MACRO and ENDM directives.
• Invocation: A macro is called by using its name in the code.
• Expansion: The assembler replaces the macro call with the actual code at assembly time
Defining a Macro
A macro is defined using the MACRO directive, followed by the macro name and
optional parameters. The macro definition ends with the ENDM directive.
SUM MACRO operand1, operand2, result
MOV AX, operand1
ADD AX, operand2
MOV result, AX
ENDM
In this example:
• The macro SUM takes three parameters: operand1, operand2, and result.
• When the macro is invoked, it generates code to add operand1 and operand2, storing
the result in result.
Invoking a Macro
A macro is invoked by simply using its name and providing the necessary arguments.
.data
num1 DW 5
num2 DW 10
sum DW 0
.code
SUM num1, num2, sum
In this example:
• The SUM macro is called with num1, num2, and sum as arguments.
• The assembler replaces the macro call with the actual code defined in the SUM
macro, resulting in the addition of num1 and num2, storing the result in sum.
Difference between Near and Far procedure
The NEAR and FAR procedures in the 8086 microprocessor are distinguished primarily by their
memory segment usage and how they handle procedure calls. Here are the key differences:
NEAR Procedure
1. Segment Location: A NEAR procedure is defined within the same code segment as the calling
instruction, often referred to as an intra-segment procedure.
2. IP Handling: When a NEAR procedure is called, only the Instruction Pointer (IP) is updated.
The old IP value is pushed onto the stack, allowing the program to return to the correct
location after the procedure execution.
3. Stack Usage: NEAR procedures require fewer stack locations since only the IP value is stored.
4. Keyword Usage: The keyword near is used in the procedure definition.
5. Example Syntax: CALL near_procedure_name
6. Return Mechanism: The return from a NEAR procedure involves popping the old IP value
from the stack back into the IP register.
FAR Procedure
1. Segment Location: A FAR procedure is defined in a different code segment than the calling
instruction, known as an inter-segment procedure.
2. CS and IP Handling: When a FAR procedure is called, both the Code Segment (CS) and IP are
updated. The old CS: IP pair is pushed onto the stack, which allows for a return to the correct
segment and instruction.
3. Stack Usage: FAR procedures require more stack locations because both the CS and IP values
need to be stored.
4. Keyword Usage: The keyword far is used in the procedure definition.
5. Example Syntax: CALL far_procedure_name
6. Return Mechanism: The return from a FAR procedure involves popping both the old IP and
CS values from the stack back into their respective registers.
Differentiate Between Re-entrant and Recursive Procedure
Recursive Procedures
A recursive procedure is one that calls itself during its execution. This self-referential behavior allows
the procedure to solve problems by breaking them down into smaller, more manageable
subproblems. Recursive procedures typically have a base case that stops the recursion to prevent
infinite loops. They are particularly useful for tasks involving complex data structures, such as trees
or graphs.
Key Characteristics of Recursive Procedures:
• Self-Calling: The procedure invokes itself.
• Base Case: Must include a termination condition to avoid infinite recursion.
• Stack Usage: Recursive calls consume stack space, which can lead to stack overflow if the
recursion depth is too high.
• Example Use Cases: Commonly used in algorithms like factorial calculation, Fibonacci series,
and tree traversals.
Re-entrant Procedures
A re-entrant procedure, on the other hand, is designed to be interrupted and safely re-entered
without losing its state. This means that if a re-entrant procedure is in the middle of execution and
an interrupt occurs (for instance, due to a hardware interrupt), the procedure can be paused, the
interrupt can be serviced, and then the procedure can resume execution without any issues.
Key Characteristics of Re-entrant Procedures:
• Interruptible: Can be interrupted and safely resumed.
• Stateless: Should not rely on global or static variables to maintain state, as these could be
altered by the interrupt.
• No Self-Modification: The procedure should not modify its own code during execution.
• Example Use Cases: Frequently used in real-time systems and applications where interrupts
are common, such as embedded systems and multi-threaded environments
Procedure and CALL/RETURN Instructions in 8086
Procedure
A procedure in 8086 assembly language is a block of code that performs a specific task. It's a
modular programming construct that promotes code reusability and organization. Procedures
are similar to functions or subroutines in higher-level programming languages.
Defining a Procedure: To define a procedure, we use the PROC and ENDP directives:
PROCEDURE_NAME PROC NEAR
; Procedure code here
PROCEDURE_NAME ENDP
CALL Instruction
The CALL instruction is used to transfer control from the main program to a procedure. When a
CALL instruction is executed, the following steps occur:
1. The address of the next instruction (return address) is pushed onto the stack.
2. The program counter (IP) is loaded with the address of the first instruction of the procedure.
Syntax:
CALL procedure_name
RETURN Instruction
The RET instruction is used to return control from a procedure back to the calling program. When
a RET instruction is executed, the return address is popped from the stack and loaded into the
program counter.
Syntax:
RET
Reentrant Procedure and Parameter Passing
Reentrant Procedure
A reentrant procedure is a subroutine that can be interrupted during execution and safely re-
entered without producing incorrect results. This is crucial in scenarios involving interrupts,
multi-tasking, or recursion.
Key characteristics of a reentrant procedure:
• No modification of global variables: Any changes to data should be made locally to avoid
conflicts with other instances of the procedure.
• Use of local variables: Data specific to each procedure invocation should be stored in local
variables on the stack.
• Avoid static data: Static data can be shared across multiple invocations, leading to potential
conflicts.
Parameter Passing to Reentrant Procedures
To ensure reentrancy, parameters should be passed to a procedure in a way that doesn't modify
the caller's data. Here are the common methods:
1. Pass by value:
o A copy of the parameter is passed to the procedure.
o Modifications to the parameter within the procedure do not affect the original value.
2. Pass by reference:
o The address of the parameter is passed to the procedure.
o The procedure can modify the original data, but this can lead to potential issues if
not handled carefully.
3. Pass by register:
o Parameters are passed through registers.
o This method is efficient but has limitations on the number of parameters that can be
passed.
Example:
; Pass by value
PROCEDURE PROC NEAR
PUSH BP
MOV BP, SP
MOV AX, [BP+4] ; Access first parameter
; ... procedure code ...
POP BP
RET 2
PROCEDURE ENDP
n the above example, the first parameter is accessed using [BP+4], which is a local variable on the
stack. This ensures that modifications to the parameter within the procedure do not affect the
original value.
Interrupt Vector Table and its Application
The Interrupt Vector Table (IVT) is a table that holds the addresses of the interrupt service routines
(ISRs) for various interrupts. It is located at the beginning of the memory (usually starting at address
0000:0000).
Applications:
• Interrupt Handling: Directs the CPU to the appropriate ISR when an interrupt occurs.
• Device Management: Manages hardware interrupts from devices like keyboards, mice, and
network cards.
• System Calls: Supports operating system services through software interrupts
Compare Procedure and Macro
An assembly program is typically divided into three main sections, each serving a distinct purpose in
the program's structure. These sections are:
1. Data Section
The data section is used for declaring initialized data or constants. This section contains variables
that hold fixed values that do not change during the execution of the program. For example, it can
include constant values, file names, or buffer sizes.
Syntax Example:
section .data
2. BSS Section
The BSS (Block Started by Symbol) section is used for declaring variables that are uninitialized. This
section reserves space in memory for variables that will be initialized at runtime but do not have a
specific value assigned at the time of declaration.
Syntax Example:
section .bss
3. Text Section
The text section contains the actual executable code of the program. This section must begin with a
declaration indicating the entry point of the program, typically using global _start or global main,
which tells the assembler where execution begins
Syntax Example:
section .text
global _start
_start:
Example:
DATA SEGMENT
MESSAGE DB 'Hello, World!', '$'
DATA ENDS
BSS SEGMENT
UNINITIALIZED_VAR DW ?
BSS ENDS
CODE SEGMENT
; executable code here
CODE ENDS
END START
Role of TEST Instruction in Assembly Language Programming
The TEST instruction performs a bitwise AND operation between two operands and sets the flags
accordingly, without modifying the operands. It is typically used for:
• Checking Specific Bits: To test if certain bits are set or cleared.
• Conditionals: Used in conditional branching based on the result of the AND operation.
TEST AX, 1 ; Test if the least significant bit of AX is
set
JZ even ; If zero flag is set, AX is even
JNZ odd ; If zero flag is not set, AX is odd
Function of Assembler Directives
Assembler directives are commands that give instructions to the assembler on how to process the
assembly language code. They do not generate machine code themselves but influence the assembly
process:
• Data Definition: Directives like DB, DW, and DD are used to define data types and initialize
variables.
• Segment Definition: Directives like SEGMENT, ENDS, and ASSUME are used to define code,
data, and stack segments.
• Constants: Directives like EQU define constants.
• Macros: Directives like MACRO and ENDM define and manage macros for code reuse.
• Assembly Control: Directives like ORG and END control the assembly process, specifying the
origin address and the end of the source code.
Compare similarities and difference between PUSH/POP and CALL/RET instructions.
The PUSH/POP and CALL/RET instructions in assembly language have some similarities and
differences:
Similarities
• Both PUSH/POP and CALL/RET instructions use the stack to store and retrieve data.
• PUSH and CALL instructions decrement the stack pointer by 2 (for 16-bit processors) to make
space for the data being pushed onto the stack.
• POP and RET instructions increment the stack pointer by 2 to remove the data from the top
of the stack.
Differences
• PUSH/POP instructions are used to store and retrieve data on the stack,
while CALL/RET instructions are used for subroutine calls and returns.
• PUSH stores the contents of a register or memory location on the stack, while CALL stores
the current value of the program counter (return address) on the stack before jumping to the
subroutine.
• POP retrieves data from the stack and stores it in a register or memory location,
while RET retrieves the return address from the stack and jumps back to the calling program.
• PUSH/POP instructions do not affect any flags, while CALL/RET instructions do not affect
flags directly.
Stack and Subroutine in 8086
Stack
A stack is a Last-In-First-Out (LIFO) data structure used for temporary storage of data during program
execution. In the 8086 microprocessor, the stack is a region of memory accessed using the Stack
Segment (SS) and Stack Pointer (SP) registers.
• SS register: Specifies the starting address of the stack segment.
• SP register: Points to the top of the stack.
The stack grows downwards in memory, meaning data is pushed onto the stack by decrementing the
SP register, and popped off by incrementing the SP register.
Basic Stack Operations:
• PUSH: Pushes a word-sized value onto the stack.
• POP: Pops a word-sized value from the stack.
Subroutine
A subroutine is a block of code that performs a specific task and can be called from different parts of
a program. It promotes modularity and code reusability.
Subroutine and Stack Interaction:
• When a subroutine is called using the CALL instruction, the return address (the address of
the next instruction after the CALL) is pushed onto the stack.
• The program counter is then loaded with the address of the first instruction of the
subroutine.
• The subroutine can use the stack to store local variables and parameters.
• When the subroutine finishes, the RET instruction pops the return address from the stack
and transfers control back to the calling program.
MAIN PROC NEAR
PUSH AX
CALL SUBROUTINE
POP AX
; ...
MAIN ENDP
SUBROUTINE PROC
NEAR
; Subroutine code
RET
SUBROUTINE ENDP
Conditional Call and Return Instructions in 8086
The 8086 microprocessors doesn't have direct conditional call or return instructions. However, you
can achieve similar functionality by combining conditional jump instructions with the regular CALL
and RET instructions.
Conditional Call
To implement a conditional call, you can use a conditional jump instruction to check a specific
condition, and if the condition is met, execute a CALL instruction to transfer control to the desired
procedure.
Example:
CMP AX, BX ; Compare AX and BX
JB LESS_THAN ; Jump to LESS_THAN if AX is less than
BX
; Continue execution if AX is not less than BX
LESS_THAN PROC NEAR
; Code for when AX is less than BX
RET
LESS_THAN ENDP
Conditional Return
Similarly, a conditional return can be achieved by using a conditional jump to a location immediately
after the RET instruction if the desired condition is not met.
Example:
MY_PROCEDURE PROC NEAR
; Procedure code
CMP RESULT, 0
JGE POSITIVE_RETURN ; Jump if result is greater than or equal to zero
; Code for negative result
POSITIVE_RETURN:
RET
MY_PROCEDURE ENDP
The Stack in 8086
The 8086 microprocessor uses a stack for temporary data storage. The stack is a Last-In-First-Out
(LIFO) data structure, meaning the last item pushed onto the stack is the first item popped off.
Key components:
• Stack Segment (SS) register: Specifies the starting address of the stack segment in memory.
• Stack Pointer (SP) register: Points to the top of the stack.
PUSH Operation
The PUSH instruction pushes a word-sized value onto the stack.
Steps involved:
1. The SP register is decremented by 2 to make space for the word to be pushed.
2. The value to be pushed is stored at the memory location pointed to by SS:SP.
Syntax:
PUSH source
source can be a register, memory location, or immediate value.
POP Operation
The POP instruction pops a word-sized value from the stack and stores it in the specified destination.
Steps involved:
1. The value at the memory location pointed to by SS:SP is copied to the destination.
2. The SP register is incremented by 2 to point to the new top of the stack.
Syntax:
POP destination
destination can be a register or memory location.
Example
PUSH AX
PUSH BX
POP CX
POP DX
In this example, the values in registers AX and BX are pushed onto the stack. Then, the values are
popped off the stack and stored in registers CX and DX, respectively.
Recursive Procedures
A recursive procedure is one that calls itself during its execution. This self-referential behaviour
allows the procedure to solve problems by breaking them down into smaller, more manageable
subproblems. Recursive procedures typically have a base case that stops the recursion to prevent
infinite loops. They are particularly useful for tasks involving complex data structures, such as trees
or graphs.
Key Characteristics of Recursive Procedures:
• Self-Calling: The procedure invokes itself.
• Base Case: Must include a termination condition to avoid infinite recursion.
• Stack Usage: Recursive calls consume stack space, which can lead to stack overflow if the
recursion depth is too high.
• Example Use Cases: Commonly used in algorithms like factorial calculation, Fibonacci series,
and tree traversals.
Example: Factorial Calculation
FACTORIAL PROC NEAR
CMP AX, 1
JLE FACTORIAL_END
PUSH AX
DEC AX
CALL FACTORIAL
POP BX
MUL BX
FACTORIAL_END:
RET
FACTORIAL ENDP
In this example:
• The base case is when AX is less than or equal to 1.
• The recursive case involves calling the FACTORIAL procedure again with AX decremented.
• The result is calculated by multiplying the current AX value with the result of the recursive
call.
Macro for 32-bit by 16-bit Division of Unsigned Numbers in Assembly Language
• We need to divide a 32-bit unsigned number by a 16-bit unsigned number.
• The 8086 DIV instruction can only handle a 32-bit dividend divided by a 16-bit divisor.
• The result (quotient) will be in AX and the remainder in DX.
DIV32_16 MACRO DIVIDEND_HI, DIVIDEND_LO, DIVISOR
; Assuming DIVIDEND_HI and DIVIDEND_LO contain the 32-bit dividend
; and DIVISOR contains the 16-bit divisor
MOV DX, DIVIDEND_HI ; Move the upper 16 bits of the dividend to DX
MOV AX, DIVIDEND_LO ; Move the lower 16 bits of the dividend to AX
DIV DIVISOR ; Divide the 32-bit dividend by the 16-bit divisor
; The quotient is now in AX and the remainder is in DX
ENDM
Here,
• The macro DIV32_16 takes three parameters: DIVIDEND_HI, DIVIDEND_LO for the 32-bit
dividend (upper and lower 16 bits) and DIVISOR for the 16-bit divisor.
• The MOV instructions load the upper 16 bits of the dividend into DX and the lower 16 bits
into AX.
• The DIV instruction performs the 32-bit by 16-bit division.
• The quotient is stored in AX and the remainder in DX.
Example:
DATA SEGMENT
NUM32_HI DW 0FFFFh
NUM32_LO DW 0ABCDh
DIVISOR DW 01234h
QUOTIENT DW ?
REMAINDER DW ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX
DIV32_16 NUM32_HI, NUM32_LO, DIVISOR
MOV QUOTIENT, AX
MOV REMAINDER, DX
; ...
CODE ENDS
END START