wok-tiny annotate bootris/stuff/tetranglix.asm @ rev 180

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