works nicely from the floppy
[bootsplash] / bootsplash.asm
1         org 7c00h
2         bits 16
3
4 BOOT_DEV equ 80h
5
6 stacktop equ 7b00h
7 boot_driveno equ 7b00h  ; 1 byte
8 stage2_size equ stage2_end - stage2_start
9
10 spawn_rate equ 512
11 framebuf equ 40000h
12
13 %macro floppy_motor_off 0
14         pushf
15         and dl, 80h
16         jnz %%end       ; skip if high bit is set (i.e. it's not a floppy)
17         mov dx, 3f2h
18         in al, dx
19         and al, 0fh
20         out dx, al
21 %%end:  popf
22 %endmacro
23
24 start:
25         xor ax, ax
26         mov ds, ax
27         mov es, ax
28         mov ss, ax
29         mov gs, ax
30         mov fs, ax
31
32         mov sp, stacktop
33         mov [boot_driveno], dl
34
35         ; load the rest of the code at 7e00
36         xor ax, ax
37         mov es, ax
38         mov bx, stage2_start
39         mov ah, 2               ; read sectors call
40         mov al, (stage2_size + 511) / 512  ; num sectors
41         mov cx, 2               ; ch: cylinder, cl: sector
42         xor dx, dx              ; dh: head
43         mov dl, [boot_driveno]
44         int 13h
45         floppy_motor_off        ; turn off floppy motor (if dl is < 80h)
46         jnc stage2_start        ; loaded successfully, jump to it
47
48         ; failed to load second sector
49         mov ax, str_load_fail
50         call printstr
51 .hang:  cli
52         hlt
53         jmp .hang
54
55         ; expects string ptr in ax
56 printstr:
57         mov si, ax
58 .loop:  mov al, [si]
59         inc si
60         test al, al
61         jz .done
62         mov ah, 0eh
63         mov bx, 7
64         int 10h
65         jmp .loop
66 .done:  ret
67
68 str_load_fail db "Failed to load second stage!",0
69 str_booting db "Booting system... ",0
70 str_bootfail db "failed!",0
71
72
73         times 510-($-$$) db 0
74 bootsig dw 0xaa55
75
76         ; start of the second stage
77 stage2_start:
78         pushf
79         cli
80         call splash
81         popf
82
83         xor ax, ax
84         mov es, ax
85         mov ds, ax
86
87         mov ax, str_booting
88         call printstr
89
90         ; blank out the existing boot signature to really see if a boot sector
91         ; gets loaded correctly
92         xor ax, ax
93         mov [bootsig], ax
94
95         ; load from BOOT_DEV into 7c00h and jump
96         mov bx, 7c00h
97         mov ax, 0201h           ; ah: call 2 (read sectors), al: count = 1
98         mov cx, 1               ; ch: cylinder 0, cl: sector 1
99         mov dx, BOOT_DEV        ; dh: head 0, dl: boot device number
100         int 13h
101         floppy_motor_off        ; turn floppy motor off (if dl < 80h)
102
103         jc .fail                ; BIOS will set the carry flag on failure
104         mov ax, [bootsig]
105         cmp ax, 0aa55h
106         jnz .fail               ; fail if what we loaded is not a valid boot sect
107
108         mov ax, 0e0dh
109         mov bx, 7
110         int 10h
111         mov ax, 0e0ah
112         int 10h
113
114         jmp 7c00h               ; all checks passed, jump there
115
116 .fail:  mov ax, str_bootfail
117         call printstr
118 .hang:  cli
119         hlt
120         jmp .hang
121
122
123         ; splash screen effect
124 splash:
125         mov ax, 13h
126         int 10h
127
128         ; setup ramdac colormap
129         mov ax, pal
130         shr ax, 4
131         mov ds, ax
132         xor ax, ax
133         mov dx, 3c8h
134         out dx, al
135         inc dx
136         xor bx, bx
137 .cmap_loop:
138         mov al, [bx]
139         shr al, 2
140         out dx, al
141         inc bx
142         cmp bx, 768     ; 256 * 3
143         jnz .cmap_loop
144
145         ; decompress image
146         mov ax, img
147         shr ax, 4
148         mov es, ax
149         xor di, di
150         mov ax, imgrle
151         shr ax, 4
152         mov ds, ax
153         xor si, si
154         mov cx, 64000
155         call decode_rle
156
157         ; precalculate spawn points
158         mov ax, es
159         mov ds, ax      ; decompressed image -> ds:bx
160         xor bx, bx
161         mov ax, spawn_pos
162         shr ax, 4
163         mov es, ax      ; spawn_pos table segment -> es:dx
164         xor edx, edx
165
166         mov cx, 64000
167 .calcspawn_loop:
168         mov al, [bx]
169         test al, 0x80
170         jz .notspawn
171         mov [es:edx * 2], bx
172         inc edx
173 .notspawn:
174         inc bx
175         dec cx
176         jnz .calcspawn_loop
177         ; update num_spawn_pos
178         xor ax, ax
179         mov ds, ax
180         mov [num_spawn_pos], edx
181
182         mov ax, framebuf >> 4
183         mov fs, ax              ; fs will point to the off-screen framebuffer
184
185         ; effect main loop
186 .mainloop:
187         mov cx, spawn_rate
188 .spawn: call rand
189         xor edx, edx
190         div dword [num_spawn_pos]       ; edx <- rand % num_spawn_pos
191         mov bx, [es:edx * 2]            ; grab one of the spawn positions
192
193         ; animate the spawn position
194         xor ax, ax
195         mov al, [frameno]
196         mov bp, ax
197         movsx ax, byte [bp + sintab]
198         sar ax, 3
199         add bx, ax
200
201         mov byte [fs:bx], 0xff          ; plot a pixel there
202         dec cx
203         jnz .spawn
204
205         ; blur the screen upwards
206         mov ax, fs
207         mov ds, ax      ; let's use ds for this to avoid long instructions
208         xor bx, bx      ; use: pointer
209         xor ax, ax      ; use: pixel accum
210         xor dx, dx      ; use: second pixel
211 .blurloop:
212         xor ax, ax
213         mov al, [bx]
214         mov dl, [bx + 320]
215         add ax, dx
216         mov dl, [bx + 319]
217         add ax, dx
218         mov dl, [bx + 321]
219         add ax, dx
220         mov dl, [bx + 640]
221         add ax, dx
222         xor dx, dx
223         mov cx, 5
224         div cx
225         mov [bx], al
226
227         inc bx
228         cmp bx, 64000 - 640
229         jnz .blurloop
230
231
232         ; wait until the start of vblank
233 .waitvblank:
234         mov dx, 3dah
235         in al, dx
236         and al, 8
237         jz .waitvblank
238
239         ; copy to screen
240         push es
241         mov ax, 0a000h
242         mov es, ax
243         xor di, di
244         mov ax, fs
245         mov ds, ax
246         xor si, si
247         mov ecx, 16000
248         rep movsd
249         pop es
250         xor ax, ax
251         mov ds, ax
252
253         inc word [frameno]
254
255         ; check for keypress
256         in al, 64h
257         and al, 1
258         jz .mainloop
259         in al, 60h
260
261 .end:   mov ax, 3
262         int 10h
263         ret
264
265         ; decode RLE from ds:si to es:di, cx: number of decoded bytes (0 means 65536)
266         ; - high bit set for the repetition count, followed by a value byte to
267         ;   be repeated N times
268         ; - high bit not set for raw data that should be copied directly
269 decode_rle:
270         mov al, [si]
271         inc si
272         mov bl, 1       ; default to "copy once" for raw values
273         test al, 0x80   ; test the high bit to see if it's a count or a raw value
274         jz .copy
275         ; it's a count, clear the high bit, and read the next byte for the value
276         and al, 0x7f
277         mov bl, al
278         mov al, [si]
279         inc si
280 .copy:  mov [es:di], al
281         inc di
282         dec cx          ; decrement decoded bytes counter
283         jz .end         ; as soon as it reaches 0, bail
284         dec bl
285         jnz .copy
286         jmp decode_rle
287 .end:   ret
288         
289
290 waitkey:
291         in al, 64h
292         test al, 1
293         jz waitkey
294         in al, 60h
295         ret
296
297 rand:
298         mov eax, [randval]
299         mul dword [randmul]
300         add eax, 12345
301         and eax, 0x7fffffff
302         mov [randval], eax
303         shr eax, 16
304         ret
305
306 randmul dd 1103515245
307 randval dd 0ace1h
308
309
310         ; data
311 %include "lut.inc"
312
313 num_spawn_pos dd 0
314 frameno dw 0
315         align 16
316 spawn_pos:
317 imgrle: incbin "nuclear.rle"
318         align 16
319 img:
320 pal:    incbin "fire.pal"
321
322 stage2_end:
323
324 ; vi:set ft=nasm: