Last active
June 12, 2019 16:42
-
-
Save strfry/a91bfba5eedadf9b1f5427ddf4f71f5b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; 8086 Snek | |
; | |
; Based on Invaders in 512 bytes by Oscar Toledo G. (c) Copyright 2015-2019 Oscar Toledo G. | |
; https://github.com/nanochess/Invaders | |
; | |
; Using PUSHA and POPA the code can be smaller, not enabled by | |
; default. | |
; | |
%ifndef pure8088 ; Define as 0 to create a 80186/80286 binary | |
pure8088: equ 1 ; Enabled by default for pure 8088 assembler | |
%endif | |
%ifndef com_file ; If not defined create a boot sector | |
com_file: equ 0 | |
%endif | |
base: equ 0xfc80 ; Memory base (same segment as video) | |
snake: equ base+0x0 ; Stores snake segments | |
; al = x, ah = y | |
snake_length: equ base+0x200 ; Length of | |
snake_offset: equ base+0x202 ; Start Offset into snake array | |
direction: equ base+0x204 ; current orientation of snake head. al = x, ah = y | |
last_frame: equ base+0x206 ; Start Offset into snake array | |
SNAKE_MAX_LENGTH: equ 256 | |
Y_HEIGHT: equ 200 ; Number of lines | |
X_WIDTH: equ 320 ; X-width of video | |
X_STRIDE: equ X_WIDTH / 4 ; X effective width in bytes | |
INTERLACE_OFFSET: equ Y_HEIGHT / 2 * X_STRIDE | |
;old_time: equ base+0x0c ; Old time | |
;level: equ base+0x10 ; Current level number | |
;lives: equ base+0x11 ; Current lives | |
;sprites: equ base+0x12 ; Space to contain sprite table | |
%if com_file | |
org 0x0100 ; Start position for COM files | |
%else | |
org 0x7c00 ; Start position for boot sector | |
%endif | |
init_gfx: | |
mov ax,0x04 ; Set mode 0x4 (320x200x2bit CGA) | |
int 0x10 ; Call BIOS | |
cld | |
; mode set through CGA port manip... | |
;mov ax, 4 | |
;mov dx, 0x03d8 | |
;out dx, ax | |
mov ax,0xb800 ; Point to screen memory | |
mov es,ax ; ...and ES | |
mov ax, 0xb000 | |
mov ds, ax ; Both DS... | |
init_snake: | |
mov word [snake_offset], 0 | |
mov word [direction], 0x0001 | |
mov si, snake | |
mov word [si+0], 0x0802 | |
mov word [si+2], 0x0803 | |
mov word [si+4], 0x0804 | |
mov word [si+6], 0x0805 | |
mov word [snake_length], 4 | |
call clear_screen | |
gameloop: | |
wait_frame: | |
mov ah,0x00 | |
int 0x1a ; BIOS clock read | |
cmp dx,[last_frame] ; Wait for change | |
je wait_frame | |
mov [last_frame],dx ; Save new current time | |
call handle_input | |
call advance_snake | |
draw: | |
call clear_screen | |
call draw_snake | |
jmp gameloop | |
; -- SubRoutines | |
; Advance Snake by one step in the ringbuffer, and move head according to [direction] | |
advance_snake: | |
mov bx, [snake_offset] ; load start offset | |
mov cx, [snake_length] ; load buffer length | |
inc bx ; increment offset | |
and bx, 0x00FF ; offset wraps around at MAX_SNAKE_LENGTH | |
mov [snake_offset], bx | |
add bx, cx ; add snake length to offset, we want to insert new element at end | |
and bx, 0x00ff ; wrap-around again | |
mov si, snake ; load array in source register | |
add si, bx ; apply offset | |
add si, bx ; twice because word | |
mov ax, [si-2] ; load previous last element (snake head) | |
mov dx, [direction] ; load direction | |
mov ch, ah ; store Y coord | |
mov ah, 0 ; wipe upper byte | |
add al, dl ; add X direction | |
mov bx, 80 ; prepare division | |
div bl ; compute wrap-around | |
mov cl, ah ; store modulus | |
mov al, ch ; load Y coord | |
mov ah, 0 ; wipe upper byte | |
add al, dh ; add Y direvtion | |
mov bx, 50 ; prepare division | |
div bl ; compute wrap-around | |
;mov ch, ah | |
mov al, cl ; restore X coord | |
mov [si], ax ; store snake head | |
ret | |
handle_input: | |
mov ah,0x01 ; BIOS Key available | |
int 0x16 | |
mov ah,0x00 ; BIOS Read Key | |
je handle_key | |
int 0x16 | |
handle_key: | |
cmp ah, 0x4d | |
mov dx, 0x0001 | |
je key_done | |
cmp ah, 0x4b | |
mov dx, 0x00ff | |
je key_done | |
cmp ah, 0x48 | |
mov dx, 0xff00 | |
je key_done | |
cmp ah, 0x50 | |
mov dx, 0x0100 | |
je key_done | |
mov dx, [direction] | |
key_done: | |
mov [direction], dx | |
ret | |
clear_screen: | |
push di | |
push cx | |
mov di, 0 | |
mov cx, Y_HEIGHT * X_STRIDE | |
clear_screen_1: | |
mov byte [es:di], 0xaa | |
inc di | |
loop clear_screen_1 | |
pop cx | |
pop di | |
ret | |
; draw the snake | |
draw_snake: | |
mov si, snake ; array base address | |
add si, [snake_offset] ; add current offset | |
add si, [snake_offset] | |
mov cx, [snake_length] ; set up counter | |
draw_snake_1: | |
lodsw | |
call big_pixel | |
loop draw_snake_1 | |
ret | |
; draw 4x4 pixel dot | |
big_pixel: | |
push bx | |
push cx | |
mov bx, ax | |
shr ax, 8 | |
mov cx, X_STRIDE * 2 | |
mul cx | |
and bx, 0x00ff | |
add ax, bx | |
mov di, ax | |
mov byte [es:di], 0xff | |
add di, X_STRIDE | |
mov byte [es:di], 0xff | |
add di, INTERLACE_OFFSET + 32 | |
mov byte [es:di], 0xff | |
add di, X_STRIDE | |
mov byte [es:di], 0xff | |
pop cx | |
pop bx | |
ret | |
%if com_file | |
%else | |
times 510-($-$$) db 0x4f | |
db 0x55,0xaa ; Make it a bootable sector | |
%endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment