it might not run on all setups because the DRM code isnt really done properly, just the bare minimum to get it going on my machine
the "PRNG" is terrible and will deadlock, fixing it has been left as an exercise to the reader :^)
format ELF64 executable 3
GAME_SPEED = 800 * 1000 * 1000 ; 0.8 second
TILE_SIZE = 64
MAX_CONNECTORS = 64
MAX_MODES = 64
MAX_SNEK = 1024
SYS_OPEN = 2
SYS_MMAP = 9
SYS_IOCTL = 16
SYS_NANOSLEEP = 35
SYS_FCNTL = 72
SYS_CLOCK_GETTIME = 228
O_RDWR = 2
O_NONBLOCK = 2048
PROT_READ = 1
PROT_WRITE = 2
MAP_SHARED = 1
TCGETS = 0x5401
F_SETFL = 4
DRM_IOCTL_MODE_GETRESOURCES = 3225445536
DRM_IOCTL_MODE_GETCONNECTOR = 3226494119
DRM_IOCTL_MODE_CREATE_DUMB = 3223348402
DRM_IOCTL_MODE_ADDFB2 = 3228067000
DRM_IOCTL_MODE_MAP_DUMB = 3222299827
DRM_IOCTL_MODE_SETCRTC = 3228066978
DRM_FORMAT_XRGB8888 = 875713112
segment readable executable
; rax = color
; rbx = framebuffer
; rcx = y
; rdx = x
; r13 = pitch
; clobbers rax, rcx, rdi, rsi
fill_tile:
push rax
push rdx
mov rax, rcx
xor rsi, rsi
mov sil, TILE_SIZE
mul rsi
mul r13
mov rdi, rbx
add rdi, rax
pop rdx
mov rax, rdx
mul rsi
xor rcx, rcx
mov cl, 4
mul rcx
add rdi, rax
pop rax
.l:
push rdi
mov cl, TILE_SIZE
rep stosd
pop rdi
add rdi, r13
dec rsi
jnz .l
xor rax, rax
xor rdi, rdi
ret
entry _start
_start:
mov al, SYS_IOCTL
mov si, TCGETS
mov rdx, termios
syscall
and byte [rdx + 12], 0xFD
mov al, SYS_IOCTL
inc si ; TCSETS
syscall
mov al, SYS_FCNTL
mov si, F_SETFL
mov rdx, O_RDWR or O_NONBLOCK
syscall
mov al, SYS_OPEN
mov rdi, [rsp + 16]
mov si, dx
syscall ; open argv[1] as card
mov rdi, rax ; save fd
mov rdx, resources
mov qword [rdx + 8], crtc + 12 ; crtc_id_ptr
mov qword [rdx + 16], conn_id ; conn_id_ptr
mov ecx, 1
mov dword [rdx + 36], ecx ; count_crtcs
mov dword [rdx + 40], MAX_CONNECTORS ; count_connectors
mov al, SYS_IOCTL
mov esi, DRM_IOCTL_MODE_GETRESOURCES
syscall
; loop thru all connectors and find first connected one
mov rbx, conn_id - 4
mov rdx, connector - 80
mov esi, DRM_IOCTL_MODE_GETCONNECTOR
.l:
add rbx, 4
add rdx, 80
mov ecx, dword [rbx] ; conn_id
mov dword [rdx + 48], ecx ; connector_id
mov dword [rdx + 32], MAX_MODES ; count_modes
mov qword [rdx + 8], modes ; modes_ptr
mov al, SYS_IOCTL
syscall
cmp dword [rdx + 60], 1
jnz .l
mov rdx, dumb
mov r12w, word [modes + 4] ; hdisplay
mov word [rdx + 4], r12w ; width
mov bp, word [modes + 14] ; vdisplay
mov word [rdx], bp ; height
mov dword [rdx + 8], 32
mov esi, DRM_IOCTL_MODE_CREATE_DUMB
mov al, SYS_IOCTL
syscall
mov r8, rdx
mov rdx, fb2
push r12
mov word [rdx + 4], r12w ; width
mov word [rdx + 8], bp ; height
mov dword [rdx + 12], DRM_FORMAT_XRGB8888 ; pixel_format
mov r12d, dword [r8 + 16] ; handle
mov dword [rdx + 20], r12d ; handles[0]
mov r13d, dword [r8 + 20] ; pitch
mov dword [rdx + 36], r13d ; pitches[0]
mov al, SYS_IOCTL
mov esi, DRM_IOCTL_MODE_ADDFB2
syscall
mov rdx, map
mov dword [rdx], r12d ; handle
mov al, SYS_IOCTL
mov esi, DRM_IOCTL_MODE_MAP_DUMB
syscall
pop r12
mov rdx, crtc
mov ecx, dword [fb2] ; fb_id
mov dword [rdx + 16], ecx ; fb_id
mov qword [rdx], rbx ; set_connectors_ptr
mov dword [rdx + 8], 1 ; count_connectors
mov dword [rdx + 32], 1 ; mode_valid
mov al, SYS_IOCTL
mov esi, DRM_IOCTL_MODE_SETCRTC
syscall
mov al, SYS_MMAP
mov rsi, qword [r8 + 24]
xchg rdi, r8
mov dl, PROT_READ or PROT_WRITE
mov r10l, MAP_SHARED
mov r9, qword [map + 8]
syscall
mov rbx, rax ; framebuffer
xor rax, rax
not rax
xor rcx, rcx
xor rdx, rdx
mov cl, 6
mov dl, 6
call fill_tile
mov byte [char], 'd'
xor r14, r14
xor r8, r8
xor r10, r10
inc r10
mov r14l, 6
mov r15, r14
mov r8l, 9
mov r9, r8
.game:
mov al, SYS_CLOCK_GETTIME
mov rsi, timespec_start
xor rdi, rdi
syscall
push rsi
.input:
xor al, al ; SYS_READ
mov rsi, char
mov rdx, 1
syscall
test rax, rax
jg .input
push r14
push r15
mov sil, [char]
cmp sil, 'w'
jz .up
cmp sil, 's'
jz .down
cmp sil, 'a'
jz .left
cmp sil, 'd'
jz .right
jmp .exit
.up:
dec r14
jmp .d
.down:
inc r14
jmp .d
.left:
dec r15
cmp r15, 0
jl .exit
jmp .d
.right:
inc r15
mov ax, r15w
inc ax
xor cx, cx
mov cl, TILE_SIZE
mul cx
cmp ax, r12w
jg .exit
.d:
cmp r14, r8
jnz .d2
cmp r15, r9
jnz .d2
inc r10
mov dil, TILE_SIZE
mov rax, r12
xor rdx, rdx
div rdi
mov rcx, rax
mov rax, rbp
xor rdx, rdx
div rdi
mov rdi, rax
; rcx = maxTilesX, rdi = maxTilesY
mov rax, 123456791
push rax
mul r9
xor rdx, rdx
div rcx
pop rax
mov r9, rdx
mul r8
xor rdx, rdx
div rdi
mov r8, rdx
xor rax, rax
not rax
pop rdx
pop rcx
push rcx
push rdx
call fill_tile
.d2:
xor rcx, rcx
pop r11 ; ox
pop rdx ; oy
.ld2:
cmp rcx, r10
je .d3
lea rsi, [snek + rcx * 2]
cmp r14, rdx
jnz .nd
cmp r15, r11
jnz .nd
jmp .exit
.nd:
xchg byte [rsi], r11l
xchg byte [rsi + 1], dl
inc rcx
jmp .ld2
.d3:
xor rax, rax
mov rcx, rdx
mov rdx, r11
call fill_tile
not rax
mov rcx, r14
mov rdx, r15
call fill_tile
not al
shl rax, 16
mov rcx, r8
mov rdx, r9
call fill_tile
pop rsi
mov al, SYS_CLOCK_GETTIME
add rsi, 16 ; timespec_end
syscall
mov rax, qword [rsi] ; timespec_end.tv_sec
sub rax, qword [rsi - 16] ; timespec_start.tv_sec
mov rcx, 1000 * 1000 * 1000
mul rcx
add rax, qword [rsi + 8] ; timespec_end.tv_nsec
sub rax, qword [rsi - 8] ; timespec_start.tv_nsec
mov rcx, GAME_SPEED
sub rcx, rax
mov qword [rsi + 24], rcx ; timespec_sleep.tv_nsec
xor rax, rax
mov al, SYS_NANOSLEEP
lea rdi, [rsi + 16] ; timespec_sleep
xor rsi, rsi
syscall
jmp .game
.exit:
xor rax, rax
mov rax, [rax]
dd 0x69696969
dw 0x6969
segment readable writeable
resources rb 64
conn_id rd MAX_CONNECTORS
connector rb 80 * MAX_CONNECTORS
dumb rb 32
fb2 rb 104
map rd 16
crtc rb 36
modes rb 69 * MAX_MODES
timespec_start rq 2
timespec_end rq 2
timespec_sleep rq 2
termios rb 60
char rb 1
snek rb MAX_SNEK * 2