Mirai's Miscellaneous Misadventures

M25 / x86 / main.s

# copyright 2022 zamfofex
# license: AGPLv3 or later

.intel_syntax noprefix
.code16

.section boot2

.global mimimi_boot
mimimi_boot:

# query disc geometry
	
	mov ah, 8
	mov dl, 0x80
	
	int 0x13
	jc mimimi_x86_exit
	cmp ah, 0
	jne mimimi_x86_exit
	
	and cl, 0x3F
	mov [sectors_per_track], cl
	inc dh
	mov [heads_per_cylinder], dh

# load parts after the bootloader
	
	mov esp, 0x7C00
	mov ebp, esp
	
	mov ax, 0x3D
	mov bx, 0x8000
	call load_data
	
	mov ax, 0x1000
	mov es, ax
	
	mov ax, 0x7D
	mov bx, 0
	call load_data
	
	mov ax, 0xBD
	mov bx, 0x8000
	call load_data
	
	mov ax, 0x2000
	mov es, ax
	
	mov ax, 0xFD
	mov bx, 0
	call load_data
	
	mov ax, 0xFD
	mov bx, 0x8000
	call load_data

# set up VESA
	
	xor eax, eax
	mov es, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	
	call 0:mimimi_vbe_set_mode
	jc mimimi_x86_exit

# establish keyboard IRQ handler
	cli
	mov [word ptr 9*4], offset handle_key
	mov [word ptr 9*4+2], 0
	sti

# set up game state
	cld
	mov eax, 0
	mov ebx, 0
	mov ecx, 0
	mov edx, 0
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	mov esp, 0x7C00
	mov ebp, esp
	call 0:mimimi_x86_start

measure_time:
	mov ah, 0x86
	mov al, 0
	mov cx, 2
	mov dx, 0
	int 0x15
	jc measure_time
	
	lfence ; rdtsc ; lfence
	mov [time], eax
	mov [time + 4], edx
	
	mov ah, 0x86
	mov al, 0
	mov cx, 0x08
	mov dx, 0x2355
	int 0x15
	jc measure_time
	
	lfence ; rdtsc ; lfence
	sub eax, [time]
	sbb edx, [time + 4]
	
	mov ecx, edx
	and ecx, 0x0F
	shl ecx, 28
	shr eax, 4
	shr edx, 4
	or eax, ecx
	
	mov [delta], eax
	mov [delta + 4], edx

loop:
	pause
	lfence ; rdtsc ; lfence
	
	cmp [time + 4], edx
	ja loop
	jb step
	cmp [time], eax
	ja loop

step:
	mov [time], eax
	mov [time + 4], edx
	
	mov eax, [delta]
	mov edx, [delta + 4]
	add [time], eax
	adc [time + 4], edx

# switch video modes
	cmp [byte ptr return], 0
	jz main
	mov [byte ptr return], 0
	call mimimi_vbe_next_mode

main:
	cld
	mov eax, 0
	mov ebx, 0
	mov ecx, 0
	mov edx, 0
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	mov esp, 0x7C00
	mov ebp, esp
	call 0:mimimi_x86_step
	
	jmp loop

lba_to_chs:
	
	push es
	push bx
	
	mov cx, ax
	
	mov bl, [sectors_per_track]
	div bl
	inc ah
	mov [sector_number], ah
	
	mov ax, cx
	mov bl, [sectors_per_track]
	div bl
	cbw
	mov bl, [heads_per_cylinder]
	div bl
	mov [cylinder_number], al
	mov [head_number], ah
	
	mov ah, 2
	mov al, 0x40
	pop bx
	mov ch, [cylinder_number]
	mov cl, [sector_number]
	mov dl, 0x80
	mov dh, [head_number]
	pop es
	
	int 0x13
	ret

load_data:
	mov ecx, 6
load_loop:
	dec ecx
	jz load_end
	
	push ecx
	call lba_to_chs
	pop ecx
	
	cmp ah, 0
	jne load_loop
load_end:
	ret

handle_key:
	pusha
	
	in al, 0x60
	
	cmp al, 0x4B
	jne break_left
	mov [byte ptr mimimi_x86_left], 1

break_left:
	cmp al, 0xCB
	jne make_right
	mov [byte ptr mimimi_x86_left], 0

make_right:
	cmp al, 0x4D
	jne break_right
	mov [byte ptr mimimi_x86_right], 1

break_right:
	cmp al, 0xCD
	jne break_return
	mov [byte ptr mimimi_x86_right], 0

break_return:
	cmp al, 0x9C
	jne handle_key_done
	mov [byte ptr return], 1

handle_key_done:
	in      al, 0x61
	mov     ah, al
	or      al, 0x80
	out     0x61, al
	mov     al, ah
	out     0x61, al
	
	mov     al, 0x20
	out     0x20, al
	
	popa
	iret

.global mimimi_x86_exit
mimimi_x86_exit:
	cli
	hlt
	jmp mimimi_x86_exit

.global mimimi_x86_left, mimimi_x86_right
mimimi_x86_left: .zero 1
mimimi_x86_right: .zero 1
return: .zero 1

sectors_per_track: .zero 1
heads_per_cylinder: .zero 1
sector_number: .zero 1
cylinder_number: .zero 1
head_number: .zero 1

delta: .zero 8
time: .zero 8