INT 10h is the BIOS video interrupt — completely separate from the DOS INT 21h family. Where INT 21h talks to the operating system, INT 10h talks directly to the video BIOS to control the screen: cursor shape, cursor position, character output, screen modes. This short program demonstrates two of those functions: setting the cursor shape and moving it to a specific screen position.
Prerequisites: Basic understanding of 8086 registers and how DOS interrupts work. Read 8086 Assembly Program to Print ‘hello’ using 09H first for context on INT 21h before tackling INT 10h.
code segment
assume cs:code
start:
mov sp, 7000h ; set up stack pointer
; BIOS INT 10h, AH=01h: Set cursor shape
mov ah, 01
mov ch, 00 ; cursor start scan line
mov cl, 14 ; cursor end scan line (0-14 = tall block cursor)
int 10h
; BIOS INT 10h, AH=02h: Set cursor position
mov ah, 02
mov bh, 00 ; display page 0
mov dh, 23 ; row 23 (decimal)
mov dl, 10 ; column 10 (decimal)
int 10h
mov ax, 4c00h
int 21h
code ends
end start
Related Links:
Understanding the two INT 10h calls
The first call uses AH=01h to set the cursor shape. On a text-mode display, the cursor is drawn as a horizontal bar whose height is defined by a pair of scan-line values. CH holds the start scan line and CL holds the end scan line (counted from the top of the character cell). Setting CH=00 and CL=14 draws a cursor that spans from the very top (line 0) to near the bottom (line 14) of the character cell — effectively a tall block cursor. Setting CH to a value with bit 5 set (like 20h) turns the cursor off entirely.
The second call uses AH=02h to move the cursor. BH specifies the display page (page 0 is the default visible page), DH specifies the row, and DL specifies the column. Note that mov dh, 23 and mov dl, 10 are decimal values here, not hex — so the cursor lands at row 23, column 10 on a standard 25-row display.
mov dh, 23 and assume hexadecimal — but MASM treats bare numbers without a trailing h as decimal. Row 23 decimal is the second-to-last row on a standard 25-row DOS screen (rows are 0-indexed, so row 24 is the last). To use hex you’d write mov dh, 17h (which is also 23 decimal). Same with mov dl, 10 — column 10 decimal, not 10h.
Output
C:TASM>debug an_bios.exe -g Program terminated normally -q
No text appears — this program moves the cursor and changes its shape, both of which are visual effects only visible on a real DOS screen or full-screen emulator. Running it under DEBUG in a window won’t show the cursor movement because the terminal intercepts the video output. To see the effect, run the EXE directly from the DOS prompt (not under DEBUG).
emu8086 version
Tested with: emu8086 v4.08, Windows 10. Use the full-screen virtual display in emu8086 to see the cursor move.
; emu8086 -- BIOS cursor shape and position
#make_COM#
org 100h
start:
; Set cursor shape: tall block (scan lines 0-14)
mov ah, 01
mov ch, 00
mov cl, 14
int 10h
; Move cursor to row 23, column 10
mov ah, 02
mov bh, 00
mov dh, 23
mov dl, 10
int 10h
mov ax, 4c00h
int 21h
NASM version
Tested with: NASM 2.16.01, DOSBox 0.74-3.
; NASM -- BIOS cursor shape and position
; nasm -f bin bios.asm -o bios.com
bits 16
org 100h
start:
mov ah, 01
mov ch, 00
mov cl, 14
int 10h
mov ah, 02
mov bh, 00
mov dh, 23
mov dl, 10
int 10h
mov ax, 4c00h
int 21h
Frequently Asked Questions
What’s the difference between INT 10h and INT 21h?
INT 10h is a BIOS interrupt — it bypasses the operating system and talks directly to the hardware (or the BIOS firmware layer). INT 21h is a DOS interrupt — it talks to DOS for higher-level services like file I/O, keyboard input, and process termination. BIOS interrupts are available even before DOS loads (they’re used in boot sectors, for example). DOS interrupts require DOS to be running. For screen output, both can be used, but INT 10h gives finer control over cursor shape, screen mode, and colour attributes.
How do I turn the cursor off completely?
Set bit 5 of CH: mov ch, 20h. When bit 5 of the cursor start scan line is set, the cursor becomes invisible. Restore it with mov ch, 00h (or whatever your original start line was) and call INT 10h AH=01h again.
Can I read the current cursor position?
Yes. INT 10h function AH=03h reads the cursor position. Set BH to the page number and call int 10h — on return, DH holds the row and DL holds the column. This is useful for saving and restoring cursor position around output routines that move it.
Conclusion
INT 10h gives you direct BIOS-level control over the cursor that INT 21h simply does not expose. The two functions here — AH=01h for cursor shape and AH=02h for cursor position — cover the most common cursor manipulation needs. The key thing to remember is that row and column values are decimal unless you explicitly append h, and that bit 5 of CH is the cursor-off switch. For any program that needs clean screen presentation, these two calls are worth keeping in your toolkit.