365 lines
5.1 KiB
NASM
365 lines
5.1 KiB
NASM
cpu 8086
|
|
bits 16
|
|
|
|
org 0x7c00
|
|
|
|
COLUMNS equ 80
|
|
ROWS equ 25
|
|
|
|
WALLPAPER equ 0x500
|
|
|
|
jmp 0:start
|
|
start:
|
|
cld
|
|
|
|
cli
|
|
|
|
; Set up segments and stack
|
|
mov ax, cs
|
|
mov ds, ax
|
|
mov es, ax
|
|
mov ss, ax
|
|
mov sp, $$
|
|
|
|
sti
|
|
|
|
; Clear BSS
|
|
mov di, _bss_start
|
|
mov cx, _bss_end - _bss_start
|
|
xor al, al
|
|
rep stosb
|
|
|
|
mov [boot_disk], dl
|
|
|
|
initialize_mouse:
|
|
; Initialize mouse
|
|
; https://www.ctyme.com/intr/rb-1601.htm
|
|
mov ax, 0xc205
|
|
mov bh, 3 ; TODO: This is the usual PS/2 mouse packet size, but is it correct here?
|
|
int 0x15
|
|
jc .error
|
|
|
|
; Set handler address
|
|
; https://www.ctyme.com/intr/rb-1603.htm
|
|
mov ax, 0xc207
|
|
; es is already set correctly
|
|
mov bx, mouse_handler
|
|
int 0x15
|
|
jc .error
|
|
|
|
; Enable mouse
|
|
; https://www.ctyme.com/intr/rb-1596.htm
|
|
mov ax, 0xc200
|
|
mov bh, 1
|
|
int 0x15
|
|
jc .error
|
|
|
|
jmp .done
|
|
|
|
.error:
|
|
; https://www.ctyme.com/intr/rb-1601.htm
|
|
mov ax, 0xc201
|
|
int 0x15
|
|
jmp initialize_mouse
|
|
|
|
.done:
|
|
|
|
load_wallpaper:
|
|
mov ax, 1
|
|
mov bl, [boot_disk]
|
|
mov cx, 8
|
|
mov di, WALLPAPER
|
|
call read_sectors
|
|
|
|
initialize_screen:
|
|
; Disable text cursor
|
|
mov ah, 0x01
|
|
mov ch, 0x20
|
|
int 0x10
|
|
|
|
call draw_wallpaper
|
|
call flip_mouse_cursor
|
|
|
|
mainloop:
|
|
mov bx, [mouse_x]
|
|
shr bx, 1
|
|
mov cx, [mouse_y]
|
|
shr cx, 1
|
|
shr cx, 1
|
|
cmp [mouse_column], bl
|
|
jne .update_cursor
|
|
cmp [mouse_row], cl
|
|
jne .update_cursor
|
|
|
|
hlt
|
|
jmp mainloop
|
|
|
|
.update_cursor:
|
|
call flip_mouse_cursor
|
|
mov [mouse_column], bl
|
|
mov [mouse_row], cl
|
|
call flip_mouse_cursor
|
|
jmp mainloop
|
|
|
|
; ------------------------------------------------------------------
|
|
; Drawing subroutines
|
|
; ------------------------------------------------------------------
|
|
|
|
draw_wallpaper:
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push es
|
|
|
|
mov bx, 0xb800
|
|
mov es, bx
|
|
|
|
mov si, WALLPAPER
|
|
xor di, di
|
|
mov cx, 80*25
|
|
rep movsw
|
|
|
|
pop es
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
|
|
flip_mouse_cursor:
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push es
|
|
|
|
mov bx, 0xb800
|
|
mov es, bx
|
|
|
|
; Column
|
|
xor bh, bh
|
|
mov bl, [mouse_column]
|
|
shl bx, 1
|
|
|
|
; Row
|
|
mov al, [mouse_row]
|
|
mov cl, COLUMNS*2
|
|
mul cl
|
|
add bx, ax
|
|
|
|
; Swap foreground and background colours
|
|
inc bx
|
|
mov al, [es:bx]
|
|
mov cl, 4
|
|
ror al, cl
|
|
mov [es:bx], al
|
|
|
|
pop es
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
|
|
; ------------------------------------------------------------------
|
|
; Disk subroutines
|
|
; ------------------------------------------------------------------
|
|
|
|
; in:
|
|
; ax = LBA of first sector
|
|
; bl = drive number
|
|
; cx = number of sectors to read (must be at least 1)
|
|
; es:di = output buffer
|
|
read_sectors:
|
|
push ax
|
|
push cx
|
|
push di
|
|
|
|
.loop:
|
|
call read_sector
|
|
inc ax
|
|
add di, 512
|
|
loop .loop
|
|
|
|
pop di
|
|
pop cx
|
|
pop ax
|
|
ret
|
|
|
|
; in:
|
|
; ax = LBA of first sector
|
|
; bl = drive number
|
|
; es:di = output buffer
|
|
read_sector:
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push dx
|
|
|
|
mov cx, 18
|
|
div cx
|
|
|
|
; cl = sector (1…18)
|
|
mov cl, dl
|
|
inc cl
|
|
|
|
; dh = head (0…1)
|
|
mov dh, 1
|
|
and dh, al
|
|
|
|
; ch = cylinder
|
|
shr ax, 1
|
|
mov ch, al
|
|
|
|
; dl = drive number
|
|
mov dl, bl
|
|
|
|
; es:bx = output buffer
|
|
mov bx, di
|
|
|
|
mov ax, 0x0201 ; read one sector
|
|
int 0x13
|
|
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
|
|
; ------------------------------------------------------------------
|
|
; Mouse callback
|
|
; ------------------------------------------------------------------
|
|
|
|
Y_OVERFLOW equ 0x80
|
|
X_OVERFLOW equ 0x40
|
|
Y_NEGATIVE equ 0x20
|
|
X_NEGATIVE equ 0x10
|
|
BUTTONS equ 0x03
|
|
|
|
X_MAX_VALUE equ 2*COLUMNS-1
|
|
Y_MAX_VALUE equ 4*ROWS-1
|
|
|
|
mouse_handler:
|
|
push ax
|
|
push bx
|
|
push bp
|
|
push ds
|
|
|
|
mov ax, cs
|
|
mov ds, ax
|
|
|
|
mov bp, sp
|
|
|
|
mov bx, [bp+18] ; status
|
|
|
|
test bl, X_OVERFLOW
|
|
jnz .x_end
|
|
.x:
|
|
mov ax, [bp+16] ; X
|
|
|
|
test bl, X_NEGATIVE
|
|
jnz .x_negative
|
|
.x_nonnegative:
|
|
add [mouse_x], ax
|
|
cmp word [mouse_x], X_MAX_VALUE
|
|
jb .x_end
|
|
mov word [mouse_x], X_MAX_VALUE
|
|
jmp .x_end
|
|
|
|
.x_negative:
|
|
neg al
|
|
sub [mouse_x], ax
|
|
jnc .x_end
|
|
mov word [mouse_x], 0
|
|
.x_end:
|
|
|
|
test bl, Y_OVERFLOW
|
|
jnz .y_end
|
|
.y:
|
|
mov ax, [bp+14] ; Y
|
|
|
|
test bl, Y_NEGATIVE
|
|
jnz .y_negative
|
|
.y_nonnegative:
|
|
; Y-axis is inverted
|
|
sub [mouse_y], ax
|
|
jnc .y_end
|
|
mov word [mouse_y], 0
|
|
jmp .y_end
|
|
|
|
.y_negative:
|
|
neg al
|
|
add [mouse_y], ax
|
|
cmp word [mouse_y], Y_MAX_VALUE
|
|
jb .y_end
|
|
mov word [mouse_y], Y_MAX_VALUE
|
|
.y_end:
|
|
|
|
and bl, BUTTONS
|
|
mov [mouse_buttons], bl
|
|
|
|
pop ds
|
|
pop bp
|
|
pop bx
|
|
pop ax
|
|
retf
|
|
|
|
; ------------------------------------------------------------------
|
|
; Debug routines
|
|
; ------------------------------------------------------------------
|
|
|
|
hexprint16:
|
|
xchg ah, al
|
|
call hexprint8
|
|
xchg ah, al
|
|
|
|
hexprint8:
|
|
push ax
|
|
push cx
|
|
mov cl, 4
|
|
shr al, cl
|
|
call hexprint4
|
|
pop cx
|
|
pop ax
|
|
|
|
hexprint4:
|
|
push ax
|
|
and al, 0xf
|
|
cmp al, 10
|
|
jb .digit09
|
|
|
|
add al, 'a' - '0' - 10
|
|
|
|
.digit09:
|
|
add al, '0'
|
|
mov ah, 0x0e
|
|
int 0x10
|
|
pop ax
|
|
ret
|
|
|
|
hang:
|
|
hlt
|
|
jmp hang
|
|
|
|
; ------------------------------------------------------------------
|
|
; Padding and boot sector signature
|
|
; ------------------------------------------------------------------
|
|
|
|
times 510-($-$$) db 0
|
|
db 0x55
|
|
db 0xaa
|
|
|
|
; ------------------------------------------------------------------
|
|
; Zero-initialized variables
|
|
; ------------------------------------------------------------------
|
|
|
|
section .bss
|
|
_bss_start:
|
|
|
|
mouse_x resw 1
|
|
mouse_y resw 1
|
|
mouse_buttons resb 1
|
|
|
|
mouse_column resb 1
|
|
mouse_row resw 1
|
|
|
|
boot_disk resb 1
|
|
|
|
_bss_end:
|