pc-timer 0.1.8

Intel 8253 programming-based timer.
Documentation
bits 16
cpu 386
org 0x100

freq equ 120 ; ticks per second

    mov ax, cs
    mov ds, ax
    cli
    mov word [low_level_ticks_per_tick], 0x1234DD / freq
    mov al, 8
    mov ah, 0x35
    int 0x21
    mov [bios_handler], bx
    mov [bios_handler+2], es
    mov ah, 0x25
    mov dx, handler_entry
    int 0x21
    mov al, 0x34
    out 0x43, al
    mov al, (0x1234DD / freq) % 256
    out 0x40, al
    mov al, (0x1234DD / freq) / 256
    out 0x40, al
    sti
wait_init:
    mov al, [init]
    test al, al
    jz wait_init
    jmp timer
prev_ticks:
    dq 0
next_ticks:
    dq 0
ticks_delta:
    dq 0
msg:
    db "000000", 0x0D, 0x0A, "$"
timer:
    cli
    mov ax, [ticks]
    mov [prev_ticks], ax
    mov ax, [ticks+2]
    mov [prev_ticks+2], ax
    mov ax, [ticks+4]
    mov [prev_ticks+4], ax
    mov ax, [ticks+6]
    mov [prev_ticks+6], ax
    sti
timer_loop:
    mov cx, 128
timer_nops:
    nop
    loop timer_nops
    cli
    mov ax, [ticks]
    mov [next_ticks], ax
    mov [ticks_delta], ax
    mov ax, [ticks+2]
    mov [next_ticks+2], ax
    mov [ticks_delta+2], ax
    mov ax, [ticks+4]
    mov [next_ticks+4], ax
    mov [ticks_delta+4], ax
    mov ax, [ticks+6]
    mov [next_ticks+6], ax
    mov [ticks_delta+6], ax
    sti
    mov bx, ticks_delta
    mov ax, [prev_ticks]
    sub [bx], ax
    mov ax, [prev_ticks+2]
    sbb [bx+2], ax
    mov ax, [prev_ticks+4]
    sbb [bx+4], ax
    mov ax, [prev_ticks+6]
    sbb [bx+6], ax
    cmp word [bx+6], 0
    jg print
    cmp word [bx+4], 0
    jg print
    cmp word [bx+2], 0
    jg print
    cmp word [bx], freq
    jl timer_loop
print:
    add byte [msg+5], 1
    cmp byte [msg+5], '9'
    jle print_msg
    mov byte [msg+5], '0'
    add byte [msg+4], 1
    cmp byte [msg+4], '9'
    jle print_msg
    mov byte [msg+4], '0'
    add byte [msg+3], 1
    cmp byte [msg+3], '9'
    jle print_msg
    mov byte [msg+3], '0'
    add byte [msg+2], 1
    cmp byte [msg+2], '9'
    jle print_msg
    mov byte [msg+2], '0'
    add byte [msg+1], 1
    cmp byte [msg+1], '9'
    jle print_msg
    mov byte [msg+1], '0'
    add byte [msg], 1
    cmp byte [msg], '9'
    jle print_msg
    mov byte [msg], '0'
print_msg:
    mov dx, msg
    mov ah, 0x09
    int 0x21
    mov ax, [next_ticks]
    mov [prev_ticks], ax
    mov ax, [next_ticks+2]
    mov [prev_ticks+2], ax
    mov ax, [next_ticks+4]
    mov [prev_ticks+4], ax
    mov ax, [next_ticks+6]
    mov [prev_ticks+6], ax
    jmp timer_loop
    db 0
ticks:
    dq 0
low_level_ticks_per_tick:
    dw 0
low_level_ticks_mod_10000h:
    dw 0
init:
    db 0
handler_entry:
    pushf
    push ds
    push bx
    push ax
    mov ax, cs
    mov ds, ax
    mov byte [init], 1
    mov bx, ticks
    add word [bx], 1
    adc word [bx+2], 0
    adc word [bx+4], 0
    adc word [bx+6], 0
    mov ax, [low_level_ticks_per_tick]
    add [low_level_ticks_mod_10000h], ax
    jnc skip_bios_handler
    pop ax
    pop bx
    pop ds
    popf
    db 0xEA
bios_handler:
    dd 0
skip_bios_handler:
    mov al, 0x20
    out 0x20, al
    pop ax
    pop bx
    pop ds
    popf
    iret