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