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:
Check Exponent: If it’s zero, stop.
Odd Case: If the current exponent is odd, multiply the running result by the current base.
Square and Halve: Regardless of odd/even, square the base and divide the exponent by 2.
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
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
In this blog post, we’ll explore an 8086 assembly program that computes the Greatest Common Divisor (GCD) of two numbers using the classic Euclidean Algorithm.
The Euclidean method is an efficient and elegant way to find the largest number that divides both inputs without leaving a remainder.
The principle is simple: GCD(A, B) = GCD(B, A mod B)
This process repeats until the remainder becomes zero. At that point, the divisor is the GCD.
Let’s dive into the code and understand how it works!
Program Code
data segment
a dw 0012h ; First number (18 decimal)
b dw 000Ah ; Second number (10 decimal)
gcd_result dw ? ; Variable to store the GCD
data ends
code segment
assume cs:code, ds:data
start:
mov ax, data
mov ds, ax ; Initialize data segment
mov ax, a ; Load A into AX
mov bx, b ; Load B into BX
cmp bx, 0000h ; Check if B is zero
jz store_result
gcd_loop:
mov dx, 0000h ; Clear DX before division
div bx ; AX = AX / BX, remainder in DX
cmp dx, 0000h ; If remainder = 0, GCD found
je store_result_bx
mov ax, bx ; A = B
mov bx, dx ; B = remainder
jmp gcd_loop ; Repeat loop
store_result_bx:
mov ax, bx ; Move GCD into AX
store_result:
mov gcd_result, ax ; Store final result
int 3 ; Stop execution
code ends
end start
In this post, we’ll walk through an 8086 assembly program that calculates the factorial of a given integer. This program highlights the power of the 8086’s loop instruction and the use of general-purpose registers for iterative calculations. We’ll use the AX register as an accumulator for the result and the CX register as a loop counter, which is its special-purpose function. Let’s get to the code!
data segment
n dw 5 ; The number to find the factorial of
fact dw ? ; To store the 16-bit result
data ends
code segment
assume ds:data, cs:code
start:
mov ax, data
mov ds, ax
mov cx, n ; Load N (5) into the counter register CX
mov ax, 1 ; Initialize factorial result (AX) to 1
fact_loop:
mul cx ; Multiply AX by CX. Result in DX:AX
loop fact_loop ; Decrement CX, jump to fact_loop if CX != 0
mov fact, ax ; Store the final result from AX into 'fact'
int 3 ; Halt execution (breakpoint for debugging)
code ends
end start
In 1978, Intel released the 8086 and changed computing permanently. It was the chip that powered the original IBM PC, seeded the x86 architecture that still runs every Windows and Linux machine today, and introduced the pipelined fetch-execute model that every modern CPU descends from. If you are studying microprocessors — for an exam, for embedded systems work, or out of curiosity about how computers actually work at the hardware level — the 8086 is where the story starts. This post covers the processor’s origin and key features first, then moves into the memory segmentation mechanism that underlies every single memory access it ever makes.
This blog post will guide you through a MASM (Microsoft Macro Assembler) program that performs the addition of two 8-bit numbers. While this is a fundamental operation, it demonstrates crucial assembly programming concepts such as data handling, register usage, and memory storage. Let’s dive in!
Assembly Code
.model small
.data
a db 09h
b db 02h
c dw ?
.code
main proc
mov ax, @data
mov ds, ax
mov al, a
mov bl, b
add al, bl
mov ah, 0
mov c, ax
int 3 ; Breakpoint interrupt
mov ax, 4C00h ; Exit program
int 21h
main endp
end main