INT 21h AH=02h writes one byte, the one in DL, to standard output. It is the smallest DOS output service and the usual building block for printing numbers: compute a digit, add "0", print it. Any byte can be written this way, "$" included, which INT 21h AH=09h cannot print.
MOV DL, "A"NEXT1:MOV AH, 02h ; DOS: print the character in DLINT 21hINC DL ; DL survives the callCMP DL, "Z"JBE NEXT1MOV DL, 13 ; CRMOV AH, 02h ; DOS: print the character in DLINT 21hMOV DL, 10 ; LFMOV AH, 02h ; DOS: print the character in DLINT 21h
DL is kept, which is why the loop can just INC DL. AL is not: DOS returns with AL holding the character just written (a tab comes back as a space), so keep nothing precious in AL across the call, and load AH again before the next one.
Control characters
| DL | On the screen |
|---|---|
| 07h | a beep; nothing is printed |
| 08h | the cursor one column left; the character there stays until overwritten |
| 09h | spaces up to the next multiple of 8 columns |
| 0Ah | line feed: one line down, the same column |
| 0Dh | carriage return: back to column 0 |
| 1Bh | with ANSI support (ANSI.SYS, or DOSBox-X's console, which has it built in): the start of an escape sequence for colours and cursor moves |
A new line in DOS is the pair 0Dh 0Ah. A line feed alone moves down without going back to the left edge, and a carriage return alone goes back along the same line. With output redirected to a file the bytes are stored exactly as sent.
Pitfalls
One character per call is slow for long texts: each call goes through the DOS dispatcher, the Ctrl+C check and the CON driver. For strings use INT 21h AH=09h or INT 21h AH=40h. MS-DOS checks the keyboard for a waiting Ctrl+C during this call, so a long printing loop can be stopped by the user; INT 21h AH=06h writes without that check. To bypass DOS altogether (no redirection, a chosen colour or position) there is the BIOS: INT 10h AH=0Eh.