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

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