DOS/BIOS Interrupts for Console I/O
Put interrupts to work — use DOS and BIOS services for keyboard input, screen output, and program control
Open interactive version (quiz + challenge)Real-world analogy
What is it?
DOS interrupts (INT 21h) and BIOS interrupts (INT 10h, INT 16h) provide ready-made services for console I/O without needing to program hardware directly. INT 21h functions handle character input (01h, 08h), string input (0Ah), character output (02h), string output (09h), and program exit (4Ch). INT 10h provides video control (cursor, colors, modes). INT 16h provides keyboard access. These are the system API of the 8086 DOS environment.
Real-world relevance
Every DOS program — from WordPerfect to early games like DOOM — used these interrupts for I/O. BIOS interrupts are still used in modern PC boot sequences (UEFI calls are the successor). Understanding these services teaches you how system calls work: user programs request OS services through a controlled interrupt interface, which is exactly how Linux (INT 80h / SYSCALL) and Windows (INT 2Eh / SYSENTER) work today.
Key points
- INT 21h — DOS Services Overview — INT 21h is the primary DOS interrupt with over 80 functions. The function number goes in AH. Common console functions: 01h (read char with echo), 02h (write char), 08h (read char no echo), 09h (write string), 0Ah (buffered input), 4Ch (exit).
- Function 01h — Read Character with Echo — Waits for a keypress, echoes the character to the screen, and returns its ASCII code in AL. If the user presses an extended key (arrow, function key), AL returns 0 and a second call returns the scan code.
- Function 02h — Write Character — Displays the character in DL at the current cursor position. The cursor advances one position. For newlines, print both CR (0Dh) and LF (0Ah). This is the simplest output function — one character at a time.
- Function 09h — Write String — Prints a '$'-terminated string at DS:DX. Faster than printing character by character. The '$' is not printed — it just marks the end. This is the most common way to display text in 8086 DOS programs.
- Function 08h — Read Character Without Echo — Like function 01h but does NOT display the typed character. Useful for password input, menu selection, or 'Press any key' prompts where you do not want the key shown on screen.
- Function 0Ah — Buffered String Input — Reads an entire line (until Enter) into a buffer. The buffer must start with max-length byte, then an empty byte for actual-length (DOS fills it). Characters follow. More practical than single-character input for names, commands, etc.
- Function 4Ch — Exit with Return Code — Terminates the program and returns control to DOS. AL holds the return code (0 = success). Batch files can check this with IF ERRORLEVEL. Always use 4Ch for clean exit — older methods (INT 20h, RET) have limitations.
- INT 10h — BIOS Video Services — INT 10h provides low-level video control through the BIOS, bypassing DOS. Function 00h sets video mode, 02h sets cursor position, 06h scrolls screen, 09h writes character with attribute, 0Eh writes in teletype mode. Gives you color and cursor control.
- INT 16h — BIOS Keyboard Services — INT 16h accesses the keyboard at the BIOS level. Function 00h waits for a key (returns ASCII in AL, scan code in AH). Function 01h checks if a key is available without waiting (ZF=0 if key ready). Lower level than DOS INT 21h keyboard functions.
- INT 10h Function 0Eh — Teletype Output — Writes a character at the current cursor position and advances the cursor automatically. Handles CR, LF, BS, and BEL control characters. Simpler than the DOS function 02h because it works without DOS — useful in boot code.
Code example
; Program: Interactive menu with colored output
; Demonstrates INT 21h and INT 10h together
.MODEL SMALL
.STACK 100h
.DATA
menu DB 0Dh, 0Ah
DB '=== 8086 I/O Demo ===', 0Dh, 0Ah
DB '1. Say Hello', 0Dh, 0Ah
DB '2. Echo input', 0Dh, 0Ah
DB '3. Colored text', 0Dh, 0Ah
DB '4. Exit', 0Dh, 0Ah
DB 'Choice: $'
hello DB 0Dh, 0Ah, 'Hello, 8086 World!', 0Dh, 0Ah, '$'
echo_p DB 0Dh, 0Ah, 'Type a char: $'
echo_r DB 0Dh, 0Ah, 'You typed: $'
color_msg DB 'COLORFUL!', 0
bye DB 0Dh, 0Ah, 'Goodbye!', 0Dh, 0Ah, '$'
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
menu_loop:
; Display menu
MOV AH, 09h
LEA DX, menu
INT 21h
; Read choice (no echo)
MOV AH, 08h
INT 21h
CMP AL, '1'
JE opt_hello
CMP AL, '2'
JE opt_echo
CMP AL, '3'
JE opt_color
CMP AL, '4'
JE opt_exit
JMP menu_loop ; invalid — show menu again
opt_hello:
MOV AH, 09h
LEA DX, hello
INT 21h
JMP menu_loop
opt_echo:
MOV AH, 09h
LEA DX, echo_p
INT 21h
MOV AH, 01h ; read with echo
INT 21h ; AL = typed character
PUSH AX
MOV AH, 09h
LEA DX, echo_r
INT 21h
POP AX
MOV DL, AL
MOV AH, 02h
INT 21h ; display the character again
JMP menu_loop
opt_color:
; Set cursor to row 12, col 30
MOV AH, 02h
MOV BH, 0
MOV DH, 12 ; row
MOV DL, 30 ; column
INT 10h
; Print each char in different color
LEA SI, color_msg
MOV BL, 09h ; starting color (bright blue)
print_color:
LODSB
CMP AL, 0
JE color_done
MOV AH, 09h ; BIOS write char + attrib
MOV BH, 0
MOV CX, 1
INT 10h
; Advance cursor manually
PUSH AX
MOV AH, 03h ; get cursor position
MOV BH, 0
INT 10h ; DH=row, DL=col
INC DL ; move right
MOV AH, 02h ; set cursor position
INT 10h
POP AX
INC BL ; next color
JMP print_color
color_done:
JMP menu_loop
opt_exit:
MOV AH, 09h
LEA DX, bye
INT 21h
MOV AX, 4C00h
INT 21h
MAIN ENDP
END MAINLine-by-line walkthrough
- 1. menu_loop: — the program loops back here after each menu option, creating an interactive menu-driven application
- 2. MOV AH, 08h / INT 21h — read choice without echo, so the typed digit is not shown (cleaner UI)
- 3. CMP AL, '1' through '4' — dispatch based on the ASCII code of the keypress. JE jumps to the matching handler
- 4. opt_echo: reads a character with function 01h (echo), then prints it again with function 02h. PUSH/POP AX preserves it across the DOS print call
- 5. INT 10h AH=02h — BIOS service to set the cursor position. DH=row, DL=column, BH=page. This positions our colored text
- 6. INT 10h AH=09h — BIOS write character with attribute. BL = color attribute (foreground + background), CX = repeat count. Unlike DOS, this does NOT advance the cursor
- 7. INT 10h AH=03h — get current cursor position so we can manually advance DL by 1 to move right after each colored character
- 8. INC BL — cycles through colors for each letter, creating a rainbow effect. BL wraps through 16 foreground colors
- 9. LODSB / CMP AL, 0 — the color_msg string is null-terminated (not '$') because we print character by character through BIOS, not DOS
- 10. MOV AX, 4C00h / INT 21h — clean exit with return code 0. AH=4Ch (function), AL=00h (return code), combined into one MOV
Spot the bug
.DATA
buf DB 10, 0, 10 DUP(0)
msg DB 'You said: $'
.CODE
MOV AH, 0Ah
LEA DX, buf
INT 21h
MOV AH, 09h
LEA DX, buf+2
INT 21hNeed a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- DOS INT 21h Function List (Wikipedia)
- BIOS Interrupt Calls (Wikipedia)
- Ralph Brown's Interrupt List (CTYME)
- DOS and BIOS Interrupts Tutorial (YouTube)