621 lines
9.1 KiB
NASM
621 lines
9.1 KiB
NASM
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, 15
|
|
|
|
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
|