Category Archives: 8086

8086 Assembly: Handling the External Timer Interrupt (INT 08h)

The 8086 processor does not poll a hardware timer on each clock tick — it reacts to one. The system timer fires INT 08h approximately 18.2 times per second, and the CPU responds by suspending whatever it is currently executing, saving its state, and running the interrupt service routine (ISR) stored at the corresponding vector. Understanding how to intercept this interrupt, execute custom logic, and then chain back to the original BIOS handler is a foundational skill in low-level 8086 programming.

This post builds a working INT 08h handler step by step. The ISR increments a counter in memory on every timer tick, displays a visible marker, and correctly chains to the original BIOS routine before returning — the safe and production-correct pattern for timer-interrupt programming.

Continue reading 8086 Assembly: Handling the External Timer Interrupt (INT 08h)

8086 Assembly: PUSH, POP, CALL, and RET – Stack Operations Explained

The stack is the workhorse of 8086 assembly. Every subroutine call, every register save-and-restore, and every return address depends on it. Understanding PUSH, POP, CALL, and RET at the instruction level — not just the high-level idea — is what separates someone who can read assembly from someone who can actually write and debug it.

In this post we build a working program that calls two subroutines, preserves registers across them, and stores results back in memory. Every line is annotated, the stack state is traced step-by-step, and the TASM/MASM debug output is shown so you can verify the execution yourself.

Continue reading 8086 Assembly: PUSH, POP, CALL, and RET – Stack Operations Explained

8086 Assembly Program to Compute the Power of a Number Using Exponentiation by Squaring

This blog post details an 8086-assembly program that computes the power of a number using the Exponentiation by Squaring algorithm (O(log n) efficiency). While a standard iterative approach multiplies the base n times (taking O(n) time), exponentiation by squaring—also known as binary exponentiation—works by breaking the exponent down into its binary components. By squaring the base in each step and only multiplying it into the result when a bit in the exponent is set, we drastically reduce the computational load. For example, calculating x32 requires only 5 multiplications instead of 31.

This example demonstrates advanced assembly concepts like bitwise manipulation, conditional branching, and efficient arithmetic optimization. Let’s get started!


Logic Breakdown:

The algorithm follows the mathematical identity of Binary Exponentiation:

  1. Check Exponent: If it’s zero, stop.
  2. Odd Case: If the current exponent is odd, multiply the running result by the current base.
  3. Square and Halve: Regardless of odd/even, square the base and divide the exponent by 2.
  4. Loop: Continue until the exponent is exhausted.

Let’s visualize it’s working for 53.

StepBase ExponentResult Action
Initial531Start loop
Iter 153 (Odd)51 X 5 = 5
Square251552 = 25,
3/2 = 1
Iter 2251 (Odd)1255 X 25 = 125
Square6250125252 = 625,
1/2 = 0
Exit0125Loop terminates
Continue reading 8086 Assembly Program to Compute the Power of a Number Using Exponentiation by Squaring

8086 Assembly Program to Compute the Power of a Number

This blog post details an 8086-assembly program that computes the power of a number, specifically baseexponent. This example demonstrates fundamental assembly concepts like loops, multiplication, and register manipulation to perform iterative arithmetic. Let’s get started!

data segment
    base dw 0003h
    exponent dw 0004h
    result dd ?
data ends

code segment
    assume cs:code, ds:data
start:
    ; Initialize data segment
    mov ax, data
    mov ds, ax

    ; Initialize result to 1 (R = B^0)
    mov word ptr result, 0001h
    mov word ptr result+2, 0000h

    ; Load base and exponent
    mov cx, exponent ; CX = exponent (loop counter)
    mov bx, base     ; BX = base

    cmp cx, 0000h
    je exit          ; If exponent is 0, result is already 1. Jump to exit.

power_loop:
    ; Multiply result by base
    ; The result is a 32-bit number in result[0] (lower word) and result[2] (upper word)
    ; Multiplication requires careful handling of the 32-bit result with a 16-bit multiplier.
    
    ; 1. Multiply the lower word of result by base
    mov ax, word ptr result ; AX = result[0]
    mul bx                  ; AX * BX -> DX:AX (32-bit product)
    push dx                 ; Save the higher word (DX) of the product
    mov word ptr result, ax ; Store the lower word (AX) of the product as the new result[0]

    ; 2. Multiply the upper word of result by base
    mov ax, word ptr result+2 ; AX = result[2]
    mul bx                    ; AX * BX -> DX:AX (32-bit product)
    
    ; 3. Add the two 16-bit 'carry' terms
    pop cx                    ; Retrieve the saved higher word (DX) from step 1 into CX
    add ax, cx                ; AX = AX + CX (Sum of two high words)
    adc dx, 0000h             ; DX = DX + 0 + Carry from the previous ADD (final carry from the 32-bit multiplication)
    
    ; 4. Store the final upper word
    mov word ptr result+2, ax ; Store AX as the new result[2]
    
    ; Handle the 32-bit overflow (DX is the final carry from the 32-bit multiplication)
    ; For a 32-bit result storage, this program assumes the result fits in 32-bits.
    ; If the power is large, overflow might occur, which is a limitation of this 32-bit storage approach.

    loop power_loop ; Decrement CX and jump back to power_loop if CX != 0

exit:
    int 3 ; Program termination
code ends
end start

Continue reading 8086 Assembly Program to Compute the Power of a Number

8086 Assembly Program to Compute Factorial of an Integer Using Recursion

This blog post will dive into a more advanced concept in 8086 assembly: computing the factorial of a number using recursion. Unlike iterative approaches using loops, recursion involves a procedure calling itself. This example highlights crucial concepts of stack management (PUSH and POP), procedure calls (CALL and RET), and conditional jumping to handle base cases. Let’s explore how the stack handles the “memory” of recursive calls!

; Program to calculate Factorial of a number using Recursion
; Input: num (e.g., 5)
; Output: result (e.g., 5! = 120 or 78h)

data segment
    num dw 0005h    ; The number to calculate factorial for (16-bit word)
    result dw ?     ; Variable to store the final 16-bit result
data ends

code segment
    assume cs:code, ds:data

start:
    mov ax, data
    mov ds, ax      ; Initialize Data Segment

    mov cx, num     ; Load the input number into CX register used as counter/argument
    mov ax, 0001h   ; Initialize accumulator AX to 1 (needed for multiplication)

    call factorial  ; Call the recursive procedure

    mov result, ax  ; Store final result from AX into memory variable
    int 3           ; Breakpoint to halt and check registers

;--- Recursive Procedure Definition ---
factorial proc near
    cmp cx, 1       ; BASE CASE: Check if number in CX is <= 1
    jbe base_case   ; If CX is 0 or 1, jump to base_case to return

    push cx         ; RECURSIVE STEP: Save current state of CX on STACK
    dec cx          ; Decrement CX to move towards base case (N-1)
    call factorial  ; Recursive Call: factorial(N-1)

    pop cx          ; UNWINDING: Restore the saved value of CX from STACK
    mul cx          ; AX = AX * CX. (Current Result * Current N)
    ret             ; Return to caller

base_case:
    mov ax, 1       ; Base case returns 1 (as 0! = 1 and 1! = 1)
    ret             ; Return to caller
factorial endp
;--------------------------------------

code ends
end start
Continue reading 8086 Assembly Program to Compute Factorial of an Integer Using Recursion

8086 Assembly Program to Generate the Fibonacci Sequence

This blog post will walk you through an 8086 assembly program designed to generate the Fibonacci sequence. While this may sound simple, it’s an excellent example for understanding looping, arithmetic operations, and register management in assembly language.

The Fibonacci Series

The Fibonacci series is a sequence where each number is the sum of the two preceding ones:

0, 1, 1, 2, 3, 5, 8, 13, 21, …

In this program, we’ll generate the first 10 Fibonacci numbers and store them in memory.


Code

; 8086 Program to Generate 10 Fibonacci Numbers
data segment
    COUNT       equ 10              ; Number of terms to generate
    FIB_SERIES  db COUNT dup(?)   ; Array to store the series
data ends

code segment
    assume cs:code, ds:data
start:
    ; Initialize Data Segment (DS) register
    mov ax, data
    mov ds, ax
    
    ; Use SI as a pointer to the array
    mov si, offset FIB_SERIES
    
    ; Seed the first two Fibonacci numbers
    ; Fib(0) = 0
    mov byte ptr [si], 00h
    
    ; Fib(1) = 1
    inc si
    mov byte ptr [si], 01h
    
    ; Set up loop counter. We already have 2 numbers,
    ; so we need to generate (COUNT - 2) more.
    mov cx, COUNT
    sub cx, 2
    
L1:
    ; AL = Fib(n-1) (e.g., [si])
    mov al, [si]
    
    ; BL = Fib(n-2) (e.g., [si-1])
    mov bl, [si-1]
    
    ; AL = Fib(n-1) + Fib(n-2)
    add al, bl
    
    ; Move pointer to next position Fib(n)
    inc si
    
    ; Store the new term: [si] = AL
    mov [si], al
    
    ; Decrement CX, loop if CX is not zero
    loop L1
    
    ; Halt execution for debugging
    int 3
    
code ends
end start
Continue reading 8086 Assembly Program to Generate the Fibonacci Sequence

8086 Assembly Program for Bitwise Operations: AND, OR, XOR, and NOT

This blog post will walk you through a simple 8086 assembly program designed to perform bitwise operations: AND, OR, XOR and NOT on 8-bit numbers. While these operations have a straightforward purpose, they are foundational when working at low level, manipulating bits, flags and registers. Let’s get started!

data segment
    a      db  0Ah        ; first 8-bit operand (10 decimal)
    b      db  05h        ; second 8-bit operand (5 decimal)
    res_and  db  ?        ; result of a AND b
    res_or   db  ?        ; result of a OR b
    res_xor  db  ?        ; result of a XOR b
    res_not  db  ?        ; result of NOT a
data ends

code segment
    assume cs:code, ds:data

start:
    mov ax, data
    mov ds, ax

    ; load operands into registers
    mov al, a
    mov bl, b

    ; AND operation: AL = AL AND BL
    and al, bl
    mov res_and, al

    ; reload operands for next operation
    mov al, a
    mov bl, b

    ; OR operation: AL = AL OR BL
    or al, bl
    mov res_or, al

    ; reload operands for next operation
    mov al, a
    mov bl, b

    ; XOR operation: AL = AL XOR BL
    xor al, bl
    mov res_xor, al

    ; NOT operation on first operand: AL = NOT AL
    mov al, a
    not al
    mov res_not, al

    int 3                ; breakpoint / stop for debug

code ends
end start
Continue reading 8086 Assembly Program for Bitwise Operations: AND, OR, XOR, and NOT