Analog clock program for MS-DOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

620 lines
9.1 KiB

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