HLT stops the processor. It fetches and executes nothing until one of three things happens: a maskable interrupt while IF = 1, a non-maskable interrupt, or a reset. On an interrupt the CPU runs the handler, and the handler's IRET returns to the instruction after HLT. From the program's point of view HLT is "wait for the next interrupt".
On a PC the timer interrupts about 18.2 times a second and every key press interrupts too, so a HLT with interrupts on lasts at most about 55 ms. Since any interrupt wakes it, put it in a loop that checks for the thing you are waiting for. The example waits about one second by watching the BIOS tick counter at 0040:006Ch.
STI ; HLT needs interrupts onPUSH DSMOV AX, 40hMOV DS, AX ; the BIOS data areaMOV BX, DS:[6Ch] ; timer ticks so farTICK1:HLT ; sleep until an interruptMOV AX, DS:[6Ch]SUB AX, BXCMP AX, 18JB TICK1 ; about one secondPOP DSMOV DX, OFFSET MSG1MOV AH, 09h ; DOS: print the string at DS:DXINT 21hMSG1 DB 'One second later', 13, 10, '$'
Pitfalls
Never HLT after CLI: with IF = 0 only an NMI or a reset can wake the CPU, and the machine looks frozen. That pairing is used deliberately only to stop a system for good. The reverse order, STI then HLT, is safe thanks to the one-instruction delay after STI.
Compared with a busy loop, HLT lets the processor idle, and later CPUs use that time to save power. Later CPUs: in protected mode HLT is privileged (ring 0 only).