INT 1Ah gives access to two different clocks. The first is the tick count, a 32-bit number at 0040:006Ch that the timer interrupt (INT 08h) increments 18.2 times a second and that starts from zero at midnight. It exists on every PC, costs nothing to read, and is the usual way to time things and to seed random numbers. The second is the real-time clock of the AT: a chip with its own battery (the Motorola MC146818 and its successors, in the CMOS) that keeps the time and date while the PC is off.
| AH | Service |
|---|---|
| 00h | read the tick count (CX:DX) and the midnight flag (AL) |
| 01h | set the tick count |
| 02h | read the RTC time: hours, minutes, seconds in BCD |
| 03h | set the RTC time |
| 04h | read the RTC date: century, year, month, day in BCD |
| 05h | set the RTC date |
| 06h / 07h | set / cancel the RTC alarm (INT 4Ah) |
Two clocks, one time
At boot the BIOS reads the RTC and sets the tick count to match, and DOS takes its time and date from there; after that the two run independently. DOS's INT 21h AH=2Ch works from the tick count, so setting the time with DOS changes the ticks but, on DOS before 3.3, not the RTC. A day has 1 573 040 (1800B0h) ticks: the timer runs at 1 193 182 Hz / 65 536 = 18.2065 Hz.
The example turns the tick count into hours and minutes. Dividing by 1092 (ticks per minute, rounded) is close enough for a clock display:
MOV AH, 00h ; BIOS: ticks since midnightINT 1Ah ; CX:DX = ticksMOV AX, DXMOV DX, CX ; DX:AX = ticksMOV BX, 1092 ; ticks per minute: 18.2065 x 60DIV BX ; AX = minutes since midnight (at most 1440)MOV BL, 60DIV BL ; AL = hours, AH = minutesMOV BH, AHXOR AH, AHCALL PDEC ; the hoursMOV DL, ":"MOV AH, 02h ; DOS: print the character in DLINT 21hMOV AL, BHXOR AH, AHCMP AL, 10 ; a leading zero for the minutesJAE TWO1MOV DL, "0"PUSH AXMOV AH, 02h ; DOS: print the character in DLINT 21hPOP AXTWO1:CALL PDEC ; the minutesPDEC PROC NEAR ; print AX in decimal; keeps every registerPUSH AXPUSH BXPUSH CXPUSH DXMOV BX, 10XOR CX, CX ; digits on the stackDECD1:XOR DX, DXDIV BX ; AX = AX / 10, DX = the last digitPUSH DXINC CXTEST AX, AXJNZ DECD1DECD2:POP DX ; the digits come back first to lastADD DL, "0"MOV AH, 02hINT 21hLOOP DECD2POP DXPOP CXPOP BXPOP AXRETPDEC ENDP
BCD
The RTC functions return binary-coded decimal: each nibble is one decimal digit, so 14 hours is 14h, 59 minutes 59h. That is convenient for display, since printing the byte as two hex digits shows the decimal number, and awkward for arithmetic. To turn a BCD byte into binary, take the high nibble times 10 plus the low nibble; AAM and AAD help.
MOV AL, CL ; a BCD byte, e.g. 59hMOV AH, ALAND AL, 0Fh ; low digit: 9MOV CL, 4SHR AH, CL ; high digit: 5AAD ; AL = AH x 10 + AL = 59 (3Bh)
In DOSBox-X
DOSBox-X takes the time from the host at start, so both clocks show the host's local time (on a server, often UTC). Its RTC is emulated in the CMOS at ports 70h and 71h, so programs that read the chip directly work too.