Module 3-1 microprocessor
Module 3-1 microprocessor
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:
2. Register-to-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 Example: MOV AX, 1234H loads the immediate value 1234H into AX.
5. Direct Addressing:
o Example: MOV AX, [1234H] moves the content from memory location 1234H to AX.
• Example: LEA AX, [BX+SI] loads the effective address formed by BX + SI into AX.
• Compares two operands and sets the flags based on the result.
Data transfer instructions are used to move data between registers, memory, and I/O ports. Some
key data transfer instructions are:
o Example: IN AL, DX (inputs a byte from the port specified by DX into AL).
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).
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.
• STOS (Store String): Stores a byte or word from the accumulator to the destination string.
• CMPS (Compare String): Compares two strings byte by byte or word by word.
5. Loop Instructions, Shift and Rotate Instructions, Logical Instructions, and Branch Instructions
Loop Instructions:
• LOOP:
• LOOPZ:
o Example: LOOPZ label decrements CX and jumps to label if CX is not zero and ZF is
set.
Logical Instructions:
• AND:
• XOR:
Branch Instructions:
• JE (Jump if Equal):
1. Problem Analysis:
2. Algorithm Development:
• Translate the algorithm into assembly language instructions using appropriate mnemonics
and syntax.
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.
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.
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
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
(i) ASSUME:
• Tells the assembler which segment registers to use for different segments.
(ii) EQU:
(v) ENDS:
o Set if there is a carry out from the most significant bit during arithmetic operations.
o Set if there is a carry from the lower nibble to the upper nibble in BCD operations.
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
4. ORG: Sets the origin (starting address) for the code or data.
These instructions are primarily used for adjusting results of arithmetic operations to accommodate
specific data formats, particularly BCD (Binary Coded Decimal) and ASCII.
• 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.
• Used after a subtraction operation to correct the result in the accumulator if it contains
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.
• Used after an addition of two ASCII digits to correct the result in the accumulator.
• 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.
• Used after a subtraction of two ASCII digits to correct the result in the accumulator.
• Clears the auxiliary carry flag (AF) if a borrow occurs from bit 4.
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
• Code Reusability: Macros promote code reusability, reducing redundancy in the code.
• Modularity: They help in breaking down complex tasks into smaller, manageable units.
• 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.
• 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.
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.
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.
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.
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.
• 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.
• 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
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 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
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.
• 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.
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 Modifications to the parameter within the procedure do not affect the original value.
2. Pass by reference:
o The procedure can modify the original data, but this can lead to potential issues if
not handled carefully.
3. Pass by register:
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.
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.
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
DATA ENDS
BSS SEGMENT
UNINITIALIZED_VAR DW ?
BSS ENDS
CODE SEGMENT
CODE ENDS
END START
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.
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.
• 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.
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
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.
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.
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.
• 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
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:
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
POSITIVE_RETURN:
RET
MY_PROCEDURE ENDP
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.
PUSH Operation
Steps involved:
Syntax:
PUSH source
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.
Syntax:
POP destination
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.
• 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.
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.
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
MOV QUOTIENT, AX
MOV REMAINDER, DX
; ...
CODE ENDS
END START