org 0x100 cpu 8086 bits 16 midpoint_x equ 160 midpoint_y equ 100 hour_hand_len equ 50 hour_hand_color equ 7 minute_hand_len equ 80 minute_hand_color equ 7 second_hand_len equ 75 second_hand_color equ 4 face_notch_len equ 8 face_notch_distance equ 90 face_notch_color equ 47 section .code setup: ; Save original video mode mov ah, 0xf int 0x10 mov [original_video_mode], al ; Move to VGA 320x200 256 color mode mov ah, 0 mov al, 0x13 int 0x10 ; Set es to point to VGA framebuffer mov ax, 0xa000 mov es, ax clockface: xor bx, bx .loop: cmp bx, 360 je .done mov word [line_sx], midpoint_x mov word [line_sy], midpoint_y mov word [line_ex], midpoint_x mov word [line_ey], midpoint_y mov ax, face_notch_distance call sinx add [line_sx], ax mov ax, face_notch_distance call cosx sub [line_sy], ax mov ax, face_notch_distance + face_notch_len call sinx add [line_ex], ax mov ax, face_notch_distance + face_notch_len call cosx sub [line_ey], ax push bx mov bl, face_notch_color call draw_line pop bx add bx, 30 jmp .loop .done: mainloop: ; Check keyboard mov ah, 6 mov dl, 0xff int 0x21 jz .no_key .key: cmp al, 'q' je exit cmp al, 27 je exit .no_key: ; Check time mov ah, 0x2c int 0x21 cmp ch, [hour] jne .changed cmp cl, [minute] jne .changed cmp dh, [second] jne .changed jmp .unchanged .changed: mov [hour], ch mov [minute], cl mov [second], dh ; Save old hand positions mov si, hour_position mov di, old_hour_position mov cx, 24 call memcpy mov ax, [hour] ; 12 hour clock face → map 12…23 to 0…11 cmp ax, 12 je .under_12 sub ax, 12 .under_12: ; 1 hour = 30° rotation of hour hand mul word [thirty] mov bx, ax ; 2 minutes = 1° rotation of hour hand mov ax, [minute] shr ax, 1 add bx, ax ; Calculate hour hand position mov ax, hour_hand_len mov bp, hour_position call calculate_hand_position ; 1 minute = 5° rotation of minute hand mov ax, [minute] mul word [six] mov bx, ax ; 12 seconds = 1° rotation of minute hand mov ax, [second] div word [twelve] add bx, ax ; Calculate minute hand position mov ax, minute_hand_len mov bp, minute_position call calculate_hand_position ; 1 second = 5° rotation of second hand mov ax, [second] mul word [six] mov bx, ax ; Calculate second hand position mov ax, second_hand_len mov bp, second_position call calculate_hand_position ; Erase hands xor bl, bl mov si, old_hour_position call draw_hand mov si, old_minute_position call draw_hand mov si, old_second_position call draw_hand ; Draw hands mov si, hour_position mov bl, hour_hand_color call draw_hand mov si, minute_position mov bl, minute_hand_color call draw_hand mov si, second_position mov bl, second_hand_color call draw_hand .unchanged: hlt jmp mainloop exit: ; Restore video mode mov ah, 0 mov al, [original_video_mode] int 0x10 ret ; in: ; cx = count ; ds:si = source ; ds:di = destination memcpy: push cx push si push di push es mov ax, ds mov es, ax rep movsb pop es pop di pop si pop cx ret ; in: ; si = points data area ; bl = color ; clobbers: ; si, di, cx draw_hand: mov di, line_sx mov cx, 8 call memcpy jmp draw_line ; in: ; ax = hand length ; bx = hand angle ; bp = points data area ; out: ; [bp] = start x ; [bp + 2] = start y ; [bp + 4] = end x ; [bp + 6] = end y calculate_hand_position: push ax push dx mov word [bp], midpoint_x mov word [bp + 2], midpoint_y mov word [bp + 4], midpoint_x mov word [bp + 6], midpoint_y mov dx, ax call sinx add [bp + 4], ax mov ax, dx call cosx sub [bp + 6], ax pop dx pop ax ret ; in: ; [line_sx], [line_sy] = starting point ; [line_ex], [line_ey] = ending point ; bl = color ; clobbers: ; [line_sx], [line_sy], [line_ex], [line_ey] draw_line: ; Bresenham's line algorithm push ax push cx push dx push bp mov ax, [line_sy] mul word [width] mov bp, ax add bp, [line_sx] ; dx = ex - sx mov dx, [line_ex] sub dx, [line_sx] mov [line_dx], dx ; dy = ey - sy mov ax, [line_ey] sub ax, [line_sy] mov [line_dy], ax .abs_dx: cmp dx, 0 jge .abs_dy neg dx .abs_dy: cmp ax, 0 jge .abs_done neg ax .abs_done: cmp ax, dx ja draw_line_high ; dy > dx draw_line_low: mov ax, [line_sx] cmp ax, [line_ex] ja draw_line_swap_start_end cmp word [line_dy], 0 jl .negative_dy .positive_dy: mov dx, [width] jmp .y_adjust_done .negative_dy: mov ax, [line_dy] neg ax mov [line_dy], ax xor dx, dx sub dx, [width] .y_adjust_done: ; errorterm = 2·dy - dx mov ax, [line_dy] add ax, [line_dy] sub ax, [line_dx] mov cx, [line_dx] test cx, cx jz draw_line_end .loop: mov byte [es:bp], bl cmp ax, 0 jle .no_y_adjust ; errorterm -= 2·dx sub ax, [line_dx] sub ax, [line_dx] ; y += y_adjust add bp, dx .no_y_adjust: ; errorterm += 2·dy add ax, [line_dy] add ax, [line_dy] ; x += 1 inc bp loop .loop jmp draw_line_end draw_line_high: mov ax, [line_sy] cmp ax, [line_ey] ja draw_line_swap_start_end cmp word [line_dx], 0 jl .negative_dx .positive_dx: mov dx, 1 jmp .x_adjust_done .negative_dx: mov ax, [line_dx] neg ax mov [line_dx], ax mov dx, -1 .x_adjust_done: ; errorterm = 2·dx - dy mov ax, [line_dx] add ax, [line_dx] sub ax, [line_dy] mov cx, [line_dy] test cx, cx jz draw_line_end .loop: mov byte [es:bp], bl cmp ax, 0 jle .no_x_adjust ; errorterm -= 2·dy sub ax, [line_dy] sub ax, [line_dy] ; x += x_adjust add bp, dx .no_x_adjust: ; errorterm += 2·dx add ax, [line_dx] add ax, [line_dx] ; y += 1 add bp, [width] loop .loop draw_line_end: pop bp pop dx pop cx pop ax ret draw_line_swap_start_end: mov ax, [line_sx] mov dx, [line_sy] xchg ax, [line_ex] xchg dx, [line_ey] mov [line_sx], ax mov [line_sy], dx pop bp pop dx pop cx pop ax jmp draw_line ; in: ; ax = scale ; bx = angle ; out: ; ax = scale·cos(angle) cosx: push bx ; cos(x) = sin(x + 90°) add bx, 90 call sinx pop bx ret ; in: ; ax = scale ; bx = angle ; out: ; ax = scale·sin(angle) sinx: push bx push dx .get_in_range: cmp bx, 360 jb .in_range sub bx, 360 jmp .get_in_range .in_range: ; sin(90°) = 1 .angle_90: cmp bx, 90 je .end ; Main branch of function 0 ≤ bx < 90 .q1: cmp bx, 90 ja .q2 ; Load sin(bx) * 2¹⁶ into bx shl bx, 1 mov bx, [sin_table + bx] ; Compute ax·bx and take high 16 bits, which cancel out the ; pre-multiplication of the sin_table mul bx mov ax, dx jmp .end ; sin(bx) = sin(180° - bx) for 90 < bx ≤ 180 .q2: cmp bx, 180 ja .q3_q4 mov dx, 180 sub dx, bx mov bx, dx call sinx jmp .end ; sin(bx) = -sin(bx - 180°) for 180 < bx < 360 .q3_q4: sub bx, 180 call sinx neg ax .end: pop dx pop bx ret section .rodata width dw 320 height dw 200 sin_table: dw 0 ; sin(0°) dw 1143 ; sin(1°) dw 2287 ; sin(2°) dw 3429 ; sin(3°) dw 4571 ; sin(4°) dw 5711 ; sin(5°) dw 6850 ; sin(6°) dw 7986 ; sin(7°) dw 9120 ; sin(8°) dw 10252 ; sin(9°) dw 11380 ; sin(10°) dw 12504 ; sin(11°) dw 13625 ; sin(12°) dw 14742 ; sin(13°) dw 15854 ; sin(14°) dw 16961 ; sin(15°) dw 18064 ; sin(16°) dw 19160 ; sin(17°) dw 20251 ; sin(18°) dw 21336 ; sin(19°) dw 22414 ; sin(20°) dw 23486 ; sin(21°) dw 24550 ; sin(22°) dw 25606 ; sin(23°) dw 26655 ; sin(24°) dw 27696 ; sin(25°) dw 28729 ; sin(26°) dw 29752 ; sin(27°) dw 30767 ; sin(28°) dw 31772 ; sin(29°) dw 32767 ; sin(30°) dw 33753 ; sin(31°) dw 34728 ; sin(32°) dw 35693 ; sin(33°) dw 36647 ; sin(34°) dw 37589 ; sin(35°) dw 38521 ; sin(36°) dw 39440 ; sin(37°) dw 40347 ; sin(38°) dw 41243 ; sin(39°) dw 42125 ; sin(40°) dw 42995 ; sin(41°) dw 43852 ; sin(42°) dw 44695 ; sin(43°) dw 45525 ; sin(44°) dw 46340 ; sin(45°) dw 47142 ; sin(46°) dw 47929 ; sin(47°) dw 48702 ; sin(48°) dw 49460 ; sin(49°) dw 50203 ; sin(50°) dw 50931 ; sin(51°) dw 51643 ; sin(52°) dw 52339 ; sin(53°) dw 53019 ; sin(54°) dw 53683 ; sin(55°) dw 54331 ; sin(56°) dw 54963 ; sin(57°) dw 55577 ; sin(58°) dw 56175 ; sin(59°) dw 56755 ; sin(60°) dw 57319 ; sin(61°) dw 57864 ; sin(62°) dw 58393 ; sin(63°) dw 58903 ; sin(64°) dw 59395 ; sin(65°) dw 59870 ; sin(66°) dw 60326 ; sin(67°) dw 60763 ; sin(68°) dw 61183 ; sin(69°) dw 61583 ; sin(70°) dw 61965 ; sin(71°) dw 62328 ; sin(72°) dw 62672 ; sin(73°) dw 62997 ; sin(74°) dw 63302 ; sin(75°) dw 63589 ; sin(76°) dw 63856 ; sin(77°) dw 64103 ; sin(78°) dw 64331 ; sin(79°) dw 64540 ; sin(80°) dw 64729 ; sin(81°) dw 64898 ; sin(82°) dw 65047 ; sin(83°) dw 65176 ; sin(84°) dw 65286 ; sin(85°) dw 65376 ; sin(86°) dw 65446 ; sin(87°) dw 65496 ; sin(88°) dw 65526 ; sin(89°) six dw 6 thirty dw 30 twelve dw 12 section .data hour dw 0 minute dw 0 second dw 0 hour_position times 4 dw 0 minute_position times 4 dw 0 second_position times 4 dw 0 old_hour_position times 4 dw 0 old_minute_position times 4 dw 0 old_second_position times 4 dw 0 line_sx dw 0 line_sy dw 0 line_ex dw 0 line_ey dw 0 line_dx dw 0 line_dy dw 0 original_video_mode db 0