Skip to content

Instantly share code, notes, and snippets.

@strfry
Last active June 12, 2019 16:42
Show Gist options
  • Save strfry/a91bfba5eedadf9b1f5427ddf4f71f5b to your computer and use it in GitHub Desktop.
Save strfry/a91bfba5eedadf9b1f5427ddf4f71f5b to your computer and use it in GitHub Desktop.
; 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