Two test cases that I created to debug the timer for the Master Control Program's boot menu default. I submitted these to a dosemu2 repo discussion.
20260114/test.asm: This is the first attempt, cut directly from the MCP development repo. (Because it uses some macros, particularly the @@ anonymous local labels, it uses the lmacros collection.) What it does: Displays a timer that counts down seconds. It attempts to count the observation of different timer tick low words in word [40h:6Ch], avoiding calculations that involve the timer tick so as to harden against running across midnight. At midnight, the entire timer tick dword wraps around from 18_00AFh or 18_00B0h to 00_0000h. (There is some disagreement as to the exact limit.)
%if 0 MCP menu timeout example 2026 by E. C. Masloch Usage of the works is permitted provided that this instrument is retained with the works, so that any entity that uses the works is notified of this instrument. DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. %endif %include "lmacros3.mac" cpu 8086 org 256 start: mov bh, 20 mov dh, 9 call showtime1 mov ax, 40h mov es, ax .resetloop: xor di, di mov cx, word [es:6Ch] .loop: mov ah, 01h int 16h jnz .keyin test bh, bh jz .timedout cmp word [es:6Ch], cx jne @F .next: sti hlt jmp .loop @@: inc di cmp di, 18 jb .next dec bh call showtime1 jmp .resetloop .timedout: .enter: mov al, dh add al, '0' jmp @F .keyin: xor ax, ax int 16h @@: mov ax, 4C00h int 21h showtime1: push si push cx mov al, 13 mov cx, 40 @@: call dispal1 mov al, 32 loop @B mov si, msg1.default.1 call display1 mov al, dh add al, '0' call dispal1 mov si, msg1.default.2.inf cmp bh, -1 je @F mov si, msg1.default.2 call display1 mov dl, 3 xor ax, ax mov al, bh call disp_ax_dec_width_dl mov si, msg1.default.3 @@: call display1 pop cx pop si retn display1: push ax .loop: cs lodsb test al, al jz .ret call dispal1 jmp .loop .ret: pop ax retn dispal1: push bx push bp mov ah, 0Eh mov bx, 7 int 10h pop bp pop bx retn disp_ax_dec_width_dl: push ax push bx push cx push dx mov bx, dx mov bh, 0 mov cx, 10 mov dx, -1 push dx .loop1: xor dx, dx div cx push dx inc bh test ax, ax jnz .loop1 sub bl, bh jbe .loop2 @@: mov al, 32 call dispal1 dec bl jnz @B .loop2: pop ax add al, '0' jc .end call dispal1 jmp .loop2 .end: pop dx pop cx pop bx pop ax retn msg1: .default.1: asciz 13,"Will choose default " .default.2: asciz " in " .default.2.inf: asciz " if Enter pressed " .default.3: asciz " seconds "
20260115/test.asm: Second attempt. This contains code I used for debugging, namely it appends the cx value read from the timer tick and the di value after incrementing the counter to an array behind the progbits part of the program. After the timeout has expired, the contents of this array are dumped as hexadecimal words. To lessen the amount of output, the timeout is decreased from 20 seconds to 10 seconds.
The uploaded test case also contains a crucial bugfix: After incrementing the di counter when its limit (18) is not yet reached, the timer tick word observed is reloaded into cx from the timer tick variable. This allows the entire timer to work reliably even when there's more IRQs or other HLT-exiting transitions than only the default 18.2 Hz IRQ #0 timer.
The labels .resetloop and .2 in this test were renamed to .loopresetdi and .loopresetcx in the actual program use case.
%if 0
MCP menu timeout example
2026 by E. C. Masloch
Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
%endif
%include "lmacros3.mac"
cpu 8086
org 256
start:
mov bp, array
mov bh, 10
mov dh, 9
call showtime1
mov ax, 40h
mov es, ax
.resetloop:
xor di, di
.2:
mov cx, word [es:6Ch]
mov word [bp], cx
inc bp
inc bp
.loop:
mov ah, 01h
int 16h
jnz .keyin
test bh, bh
jz .timedout
cmp word [es:6Ch], cx
jne @F
.next:
sti
hlt
jmp .loop
@@:
inc di
mov word [bp], di
inc bp
inc bp
cmp di, 18
jb .2
dec bh
call showtime1
jmp .resetloop
.timedout:
.enter:
mov al, dh
add al, '0'
jmp @F
.keyin:
xor ax, ax
int 16h
@@:
mov si, msg1.linebreak
call display1
dump:
mov si, array
xor cx, cx
.loop:
cmp si, bp
jae .end
mov al, 32
call dispal1
lodsw
call disp_ax_hex
inc cx
test cl, 7
jnz .next
push si
mov si, msg1.linebreak
call display1
pop si
.next:
jmp .loop
.end:
mov si, msg1.linebreak
call display1
mov ax, 4C00h
int 21h
showtime1:
push si
push cx
mov al, 13
mov cx, 40
@@:
call dispal1
mov al, 32
loop @B
mov si, msg1.default.1
call display1
mov al, dh
add al, '0'
call dispal1
mov si, msg1.default.2.inf
cmp bh, -1
je @F
mov si, msg1.default.2
call display1
mov dl, 3
xor ax, ax
mov al, bh
call disp_ax_dec_width_dl
mov si, msg1.default.3
@@:
call display1
pop cx
pop si
retn
disp_ax_hex:
xchg al, ah
call disp_al_hex
xchg al, ah
disp_al_hex:
push cx
mov cl, 4
rol al, cl
call disp_al_nybble_hex
rol al, cl
pop cx
disp_al_nybble_hex:
push ax
push dx
and al, 15
add al, '0'
cmp al, '9'
jbe .got
add al, 7
.got:
call dispal1
pop dx
pop ax
retn
display1:
push ax
.loop:
cs lodsb
test al, al
jz .ret
call dispal1
jmp .loop
.ret:
pop ax
retn
dispal1:
push bx
push bp
mov ah, 0Eh
mov bx, 7
int 10h
pop bp
pop bx
retn
disp_ax_dec_width_dl:
push ax
push bx
push cx
push dx
mov bx, dx
mov bh, 0
mov cx, 10
mov dx, -1
push dx
.loop1:
xor dx, dx
div cx
push dx
inc bh
test ax, ax
jnz .loop1
sub bl, bh
jbe .loop2
@@:
mov al, 32
call dispal1
dec bl
jnz @B
.loop2:
pop ax
add al, '0'
jc .end
call dispal1
jmp .loop2
.end:
pop dx
pop cx
pop bx
pop ax
retn
msg1:
.default.1: asciz 13,"Will choose default "
.default.2: asciz " in "
.default.2.inf: asciz " if Enter pressed "
.default.3: asciz " seconds "
.linebreak: asciz 13,10
align 2, db 0
array: