wok-tiny view bootris/stuff/tetranglix.asm @ rev 183

linux: fix bundle.S
author Pascal Bellard <pascal.bellard@slitaz.org>
date Tue Sep 26 17:09:38 2023 +0000 (7 months ago)
parents bbb34fe4904d
children 61c76233911e
line source
1 ; Modified by nanochess for compatibility with VirtualBox.
2 ; to require only 8086 and also now it's in color.
4 BITS 16
6 BSS EQU 0x7E00
7 BSS_SIZE EQU 438
9 CUR_TETRAMINO EQU BSS ; 16 bytes.
10 ROT_TETRAMINO EQU BSS + 16 ; 16 bytes.
11 OFFSET EQU BSS + 32 ; 2 bytes.
12 STACK EQU BSS + 38 ; 4 bytes reserved in beginning, 400 bytes.
14 LEFT_SCANCODE EQU 0x4b
15 RIGHT_SCANCODE EQU 0x4d
17 UP_SCANCODE EQU 0x48
18 DOWN_SCANCODE EQU 0x50
20 SCORE_DIGITS EQU 5
22 SCREEN_SEGMENT EQU 0xB800
24 CPU 8086
26 ; Entry point.
27 ; cs:ip -> linear address (usually 0x7C00, but irrelevant because we are position independent).
28 start:
29 ; Stack.
30 push cs
31 pop ss
32 mov sp, SCREEN_SEGMENT ;why not
34 push cs
35 pop ds
36 push cs
37 pop es
39 ; Clear direction flag.
40 cld
42 ; Allow interrupts
43 sti
45 ; Clear BSS
46 mov di, BSS
47 mov cx, di ;at least BSS_SIZE
48 xor ax, ax
49 rep stosb
51 ; Set to mode 0x03, or 80x25 text mode (ah is zero from above).
52 mov al, 0x03
53 int 0x10
55 ; Hide the hardware cursor.
56 mov ch, 0x26
57 mov ax, 0x103 ; Some BIOS crash without the 03.
58 int 0x10
60 mov es, sp
62 ; White spaces on black background.
63 xor di, di
64 mov ax, 0x0F00
65 mov ch, 8 ; At least 80x25x2.
66 rep stosw
67 call pop_check
69 ; Detects if CUR_TETRAMINO at OFFSET is colliding with any thing.
70 ; si -> OFFSET.
71 ; Output:
72 ; Carry set if colliding.
73 tetramino_collision_check:
75 lea bx, [bp + check_collision - tetramino_collision_check]
77 ; Processes the current tetramino, calling bx per "tetramino pixel".
78 ; bx -> where to call to; al contains tetramino pixel, di the address into stack.
79 tetramino_process:
80 push si
81 push ax
82 push di
83 push cx
85 ; Gets the offset into stack (i.e., address) into di.
86 ; si -> points at OFFSET.
87 ; Output:
88 ; si -> points at CUR_TETRAMINO.
89 ; di -> address into stack.
90 ; Trashes ax.
92 ; Calculate first index into screen.
93 lodsw
94 aad 0x10
96 mov cl, 0x10
98 cmp [si-1], cl
99 sbb ah, ah
100 xchg bx, ax
101 lea di, [si + (STACK - OFFSET) + 0xFE + bx]
102 xchg bx, ax
104 mov si, CUR_TETRAMINO
106 .loop:
107 test cl, 0x13;0b1011
108 jnz .load_loop
110 ; Go to next line in stack.
111 add di, 16 - 4
113 .load_loop:
114 lodsb
116 ; Call wherever the caller wants us to go.
117 call bx
119 inc di
120 loop .loop
122 pop cx
123 pop di
124 pop ax
125 pop si
126 ret
128 check_collision:
129 or al,al
130 jz .clear_carry
132 cmp di, STACK + 400
133 jae .colliding
135 cmp byte [di],0
137 .clear_carry:
138 ;clc
140 je .next_iter
142 ; Colliding!
143 .colliding:
145 stc
146 mov cl, 1
147 .next_iter:
148 ret
150 ; Used by the stack joining part.
151 merge:
152 or [di], al
153 ret
155 exit_game_over:
156 je start
157 exit_dos:
158 mov al,0x03 ; Clear screen
159 int 0x10
160 int 0x20 ; Return to bootOS
161 int 0x19
163 ; All tetraminos in bitmap format.
164 tetraminos:
165 db 0xF0;0b11110000 ; I
166 db 0xE2;0b11100010 ; J
167 db 0x2E;0b00101110 ; L
168 db 0x66;0b01100110 ; O
169 db 0x36;0b00110110 ; S
170 db 0xE4;0b11100100 ; T
171 db 0x63;0b01100011 ; Z
173 pop_check:
174 pop bp ; Save some bytes.
176 .borders:
177 mov si, STACK - 3
178 mov ax, 0x0101
180 .borders_init:
181 mov [si], ax
182 mov [si + 2], ax
183 mov [si + 4], ax
185 add si, 16
186 cmp si, STACK + 400 - 3
187 jbe .borders_init
189 ; Cleared dl implies "load new tetramino".
190 xor dl, dl
192 .event_loop:
193 mov si, OFFSET
195 ; For some reason this doesn't work with BootOS over VirtualBox 5.1.22
196 %ifdef READ_PIT
197 mov bx, [0x046C]
198 inc bx
199 inc bx ; Wait for 2 PIT ticks.
201 .busy_loop:
202 cmp [0x046C], bx
203 jne .busy_loop
204 %else
205 push dx
206 clc
207 mov bx,0x1000
208 .busy_loop2:
209 pushf
210 .busy_loop1:
211 hlt ; Wait for clock interrupt
212 mov ah,0x00
213 int 0x1a
214 cmp [bx],dx
215 je .busy_loop1
216 mov [bx],dx
217 popf
218 cmc
219 jc .busy_loop2
220 pop dx
221 xor cx,cx ; Or rotation doesn't work
222 %endif
223 ; If we don't need to load a new tetramino, yayy!
224 test dl, dl
225 jnz .input
227 ; Load a tetramino to CUR_TETRAMINO, from the compressed bitmap format.
229 .choose_tetramino:
230 in al,(0x40)
232 ; Only 7 tetraminos, index as 1-7.
233 %ifdef READ_PIT
234 and ax, 7
235 %else
236 and al, 7 ; ah = 0
237 %endif
238 je .choose_tetramino
240 ; Get the address of the tetramino (in bitmap format).
241 cwd
242 mov di,ax
243 mov ah,al
245 ; Load tetramino bitmap in dl.
246 mov dl, [bp + di + (tetraminos - tetramino_collision_check) - 1]
247 mov cl, 4
248 shl dx, cl
250 ; Convert from bitmap to array.
251 mov di, CUR_TETRAMINO
252 mov cl, 0x10
254 .loop_bitmap:
256 shl dx, 1
258 ; If the bit we just shifted off was set, store number of tetramino.
259 sbb al, al
260 and al, ah
261 mov [di], al
262 inc di
264 loop .loop_bitmap
266 ; Loaded.
267 mov dl, 6
269 mov word [si], dx
270 jmp .link_next_iter
272 ; Check for input.
273 .input:
274 ; Check for keystroke.
275 mov ah, 0x01
276 int 0x16
278 ; If no keystroke, increment vertical offset.
279 jz .vertical_increment
281 ; Clear the keyboard buffer.
282 xor ah, ah
283 int 0x16
285 .exit:
286 dec ah
287 je exit_dos
288 mov al, ah
290 ; Go left.
291 .left:
292 cmp al, LEFT_SCANCODE-1
293 je .call_bp
295 ; Go right.
296 .right:
297 cmp al, RIGHT_SCANCODE-1
298 jne .rotate
300 add byte [si],2
302 .call_bp:
303 dec byte [si]
304 xor al, (LEFT_SCANCODE-1) ^ (RIGHT_SCANCODE-1)
305 call bp
306 jc .left
308 ; Rotate it.
309 .rotate:
310 cmp al, UP_SCANCODE-1
311 jne .vertical_increment
313 inc cx
315 .rotate_loop:
316 ; Rotates CUR_TETRAMINO 90 degrees clock-wise.
317 ; Output:
318 ; CUR_TETRAMINO -> rotated tetramino.
319 push si
320 push di
321 push cx
322 push es
324 ; Reset ES.
325 push ds
326 pop es
328 mov si, CUR_TETRAMINO
329 mov di, ROT_TETRAMINO + 3
330 push si
331 mov cl, 4
333 .loop:
334 mov ch, 4
336 .tetramino_line:
337 movsb
338 scasw
339 inc di
340 dec ch
341 jnz .tetramino_line
343 sub di, 4*4+1
344 loop .loop
346 pop di
347 mov cl, 4*4/2 ; CH would be zero, from above.
348 rep movsw
350 pop es
351 pop cx
352 pop di
353 pop si
355 loop .rotate_loop
357 call bp
358 ; To restore, just rotate 3 more times.
359 mov cl, 3
360 jc .rotate_loop
362 .vertical_increment:
363 mov cl, 1
364 call upd_score
366 ; Check if we can go below one byte, successfully.
367 inc byte [si + 1]
368 call bp
369 .link_next_iter:
370 jnc .next_iter
372 ; If we can't, we need a new tetramino.
373 dec byte [si + 1]
374 je .game_over
375 cwd
377 ; Joins the current tetramino to the stack, and any complete lines together.
378 ; si -> OFFSET.
379 push es
381 push ds
382 pop es
384 lea bx, [bp + merge - tetramino_collision_check]
385 call tetramino_process
387 mov si, STACK + 15
388 std
390 .loop_lines:
391 push si
392 mov cl, 16
394 .line:
395 lodsb
396 test al, al
397 loopnz .line ; If it was a blank, exit loop to indicate failure.
399 jz .next_line
401 lea cx, [si - (STACK - 1)]
402 lea di, [si + 16]
403 rep movsb
404 mov cl, 64
405 call upd_score
407 .next_line:
408 pop si
409 add si, 16
410 cmp si, STACK + 15 + 400
411 jb .loop_lines
413 cld
414 pop es
416 jmp .borders
418 .game_over: ; Game Over
419 xor ax, ax
420 int 0x16 ; wait for a key
421 dec ah
422 jmp exit_game_over
424 .next_iter:
425 ; Display the stack.
426 push si
428 ; Add 24 characters padding in the front.
429 mov ah, 0x0F
430 mov di, 48
431 mov si, STACK
433 .loop_stack_lines:
434 ; Copy 32 characters.
435 mov cl, 16
437 .stack_line:
438 lodsb
439 mov ah,al
440 mov al,0xdb
441 ; Store one character as two -- to make stack "squarish" on 80x25 display.
442 stosw
443 stosw
445 loop .stack_line
447 ; Handle remaining 24 characters in row, and starting 24 in next row.
448 add di, 96
449 cmp di, (25 * 160) ; If we go beyond the last row, we're over.
450 jb .loop_stack_lines
452 pop si
454 ; Displays CUR_TETRAMINO at current OFFSET.
455 ; si -> OFFSET.
457 ; Calculate first index into screen.
458 mov al, 40
459 mul byte [si+1]
460 mov cl, 12
461 add cl, [si]
462 add ax, cx
464 ; One character takes 2 bytes in video memory.
465 shl ax, 1
466 shl ax, 1
467 xchg di, ax
469 ; Loops for 16 input characters.
470 mov cl, 0x10
471 mov si, CUR_TETRAMINO
473 mov ah, 0x0F
475 .loop_tetramino:
476 test cl, 0x13;0b1011
477 jnz .load_tetramino
479 ; Since each tetramino input is 4x4, we must go to next line
480 ; at every multiple of 4.
481 ; Since we output 2 characters for one input char, cover offset of 8.
482 add di, (80 - 8) * 2
484 .load_tetramino:
485 lodsb
486 or al,al
487 mov ah,al
488 mov al,0xdb
489 ; Output two characters for "squarish" output.
490 jne .load_tetramino2
491 mov ax, [es:di]
492 .load_tetramino2:
493 stosw
494 stosw
496 loop .loop_tetramino
498 jmp .event_loop
500 upd_score:
501 push ds
502 mov bx, SCREEN_SEGMENT
503 mov ds, bx
504 mov bx, SCORE_DIGITS * 2
506 .chk_score:
507 dec bx
508 dec bx
509 js pop_check.game_over
510 mov al, '0'
511 xchg [bx], al
512 or al, 0x30
513 cmp al, '9'
514 je .chk_score
515 inc ax
516 mov [bx], al
517 pop ds
519 loop upd_score
520 ret
522 ; IT'S A SECRET TO EVERYBODY.
523 db "ShNoXgSo"
525 ; Padding.
526 times 510 - ($ - $$) db 0
528 BIOS_signature:
529 dw 0xAA55