41 Commits

Author SHA1 Message Date
PoliEcho 82e55b3e1e Merge branch 'master' of https://git.pupes.org/PoliEcho/asm-game-of-life
build_test / build (push) Successful in 2m11s
2025-07-14 20:57:01 +02:00
PoliEcho 6d3279f850 add tty workaround 2025-07-14 20:55:41 +02:00
PoliEcho 1820d4fdf8 Update README.md
build_test / build (push) Successful in 1m58s
2025-07-13 22:18:00 +00:00
PoliEcho 81367baa99 Update README.md
build_test / build (push) Successful in 1m48s
2025-07-13 22:16:01 +00:00
PoliEcho 33b6a82a42 Update README.md
build_test / build (push) Successful in 2m2s
2025-07-13 22:12:02 +00:00
PoliEcho 755f9b9f06 Update README.md
build_test / build (push) Successful in 1m54s
2025-07-13 22:03:09 +00:00
PoliEcho c3563fcda1 Update README.md
build_test / build (push) Successful in 2m18s
2025-07-13 21:57:45 +00:00
PoliEcho 719bc17fcd Update README.md
build_test / build (push) Successful in 2m16s
2025-07-13 21:36:34 +00:00
PoliEcho 5c91ace69b change statusbar text
build_test / build (push) Successful in 3m11s
2025-07-13 22:35:22 +02:00
PoliEcho 872c842e7c revert input.asm 2025-07-13 21:07:48 +02:00
PoliEcho a6a7debf2e break tty while trining to fix tty 2025-07-13 20:23:19 +02:00
PoliEcho 57987228b0 add simulation speed
build_test / build (push) Successful in 2m58s
2025-07-13 14:27:46 +02:00
PoliEcho 83d3f3ac5a Update README.md
build_test / build (push) Successful in 1m55s
2025-07-12 20:02:03 +00:00
PoliEcho 45c6d0eb83 Update README.md
build_test / build (push) Successful in 2m3s
2025-07-12 19:54:03 +00:00
PoliEcho 670a6a2602 Add README.md
build_test / build (push) Has been cancelled
2025-07-12 19:53:40 +00:00
PoliEcho e70b9ac765 Update .gitea/workflows/build_test.yaml
build_test / build (push) Successful in 1m57s
2025-07-12 19:47:20 +00:00
PoliEcho 6112537e9b Update .gitea/workflows/build_test.yaml
build_test / build (push) Failing after 2m22s
2025-07-12 19:42:41 +00:00
PoliEcho 3e59f36d4e Update .gitea/workflows/build_test.yaml
build_test / build (push) Failing after 23s
2025-07-12 19:41:46 +00:00
PoliEcho f26553e7c7 Update .gitea/workflows/build_test.yaml
build_test / build (push) Failing after 14s
2025-07-12 19:40:32 +00:00
PoliEcho db00e98b4c Update .gitea/workflows/build_test.yaml 2025-07-12 19:39:08 +00:00
PoliEcho b449c66a66 Update .gitea/workflows/build_test.yaml 2025-07-12 19:38:24 +00:00
PoliEcho 7dc5237c3e Update .gitea/workflows/build_test.yaml
build_test / build (push) Failing after 13s
2025-07-12 19:37:10 +00:00
PoliEcho 7fd699ea38 Update .gitea/workflows/build_test.yaml
build_test / build (push) Failing after 34s
2025-07-12 19:34:56 +00:00
PoliEcho b5c539a3a2 Update .gitea/workflows/build_test.yaml
build_test / build (push) Failing after 18s
2025-07-12 19:33:30 +00:00
PoliEcho ce343ff9db Update .gitea/workflows/build_test.yaml
build_test / build (push) Failing after 57s
fix build test
2025-07-12 18:59:23 +00:00
PoliEcho d6ee106682 add build test
build_test / build (push) Failing after 1m9s
2025-07-12 20:56:47 +02:00
PoliEcho 5b56f6bcb6 fix some rendering issues 2025-07-12 20:11:22 +02:00
PoliEcho 4a8db75bef make multipurpuse_buf biger to avoid out of bounds writes 2025-07-12 17:12:25 +02:00
PoliEcho fa7b4c70b8 IT WORKS 2025-07-12 16:09:39 +02:00
PoliEcho a46f907ff6 fixing segfault and such 2025-07-12 11:47:57 +02:00
PoliEcho 63ded22bfd more work on actual game logic 2025-07-10 22:55:18 +02:00
PoliEcho 00cc777183 add warning flags 2025-07-10 20:59:32 +02:00
PoliEcho b94ebe30c8 add user input handling 2025-07-10 18:27:52 +02:00
PoliEcho c5e404f1dd FINALY fix inicializing gameboard 2025-07-09 21:33:36 +02:00
PoliEcho 564a6b88c1 fix aligment 2025-07-09 20:34:24 +02:00
PoliEcho d6613ac341 fix memory_set number 2 2025-07-09 20:34:09 +02:00
PoliEcho 2b8236ee91 fix memory_set function 2025-07-09 19:23:13 +02:00
PoliEcho c0bd3fcbc3 fix pointer aritmetic 2025-07-09 13:26:06 +02:00
PoliEcho 76093db3c9 YES IT DOES NOT SEGFAULT 2025-07-08 22:50:46 +02:00
PoliEcho 9092d1276a added memory_set'function 2025-07-08 15:04:23 +02:00
PoliEcho 35a6894d9f fix allocator 2025-07-08 10:00:24 +02:00
9 changed files with 908 additions and 37 deletions
+17
View File
@@ -0,0 +1,17 @@
name: build_test
on: [push]
jobs:
build:
runs-on: arch
steps:
- name: fix package cache
run: rm -fr /var/cache/pacman/pkg/* && pacman -Syy archlinux-keyring --needed --noconfirm && pacman-key --init && pacman-key --populate archlinux
- name: get dependencies
run: pacman -Sy nodejs make nasm binutils --needed --noconfirm
- name: Checkout code
uses: actions/checkout@v4
- name: Build
run: make -j$(nproc)
+11 -1
View File
@@ -1,12 +1,22 @@
NASM = nasm NASM = nasm
LD = ld LD = ld
NASM_FLAGS := -felf64 -Isrc NASM_FLAGS := -felf64 -Isrc -Ox -Ov -w+all -w-reloc-abs-dword -w-reloc-rel-dword
LD_FLAGS := --strip-all LD_FLAGS := --strip-all
DEBUG_LD_FLAGS := -g DEBUG_LD_FLAGS := -g
DEBUG_NASM_FLAGS := -g -F dwarf DEBUG_NASM_FLAGS := -g -F dwarf
# check for avx2 support
ifeq ($(shell grep -o 'avx2[^ ]*' /proc/cpuinfo | head -n 1),avx512)
NASM_FLAGS += -DAVX2
endif
# check for avx512 support
ifeq ($(shell grep -o 'avx512[^ ]*' /proc/cpuinfo | head -n 1),avx512)
NASM_FLAGS += -DAVX512
endif
SRC_PATH := src SRC_PATH := src
OBJ_PATH := build/obj OBJ_PATH := build/obj
+35
View File
@@ -0,0 +1,35 @@
<img src="https://git.pupes.org/repo-avatars/e4ede9d30f070c9e191eace5a88dcaa40434b9cadf60204122fab5a83aec9a9f" alt="logo of ParaDocs" width="196"></img>
[![build test](https://git.pupes.org/PoliEcho/asm-game-of-life/actions/workflows/build_test.yaml/badge.svg)](https://git.pupes.org/PoliEcho/asm-game-of-life/actions?workflow=build_test.yaml)
# AMD64 Assembly Game of life
## Dependencies
> AMD64 Linux Kernel
### Build only
> nasm
> ld
> make
## Download
[releases](https://git.pupes.org/PoliEcho/asm-game-of-life/releases)
## Build
```shell
make
```
## Controls
| key | action |
|--------|-------------------------|
| arrows | move cursor |
| ENTER | invert cell |
| j/k | change simulation speed |
| p | start/stop simulation |
| q | quit |
## Warning
delays in TTY may be broken
## Notes
if screen does not clear properly after loading just move the cursor around a bit
+4 -3
View File
@@ -7,7 +7,7 @@ section .text
global init_alloc global init_alloc
init_alloc:; initialize allocator, optionaly return brk pointer in rax init_alloc:; initialize allocator, optionaly return brk pointer in rax
mov rax, SYS_BRK mov rax, SYS_BRK
mov rdi, 0 xor rdi, rdi
syscall syscall
mov [brk_pointer], rax mov [brk_pointer], rax
ret ret
@@ -15,9 +15,10 @@ init_alloc:; initialize allocator, optionaly return brk pointer in rax
global alloc global alloc
alloc:; Takes lenght of data in rdi and returns pointer in rax alloc:; Takes lenght of data in rdi and returns pointer in rax
mov rax, SYS_BRK mov rax, SYS_BRK
mov rcx, [brk_pointer] mov qword rcx, [brk_pointer]
push rcx push rcx
syscall; size already in rdi add rdi, rcx; calculate new BRK address
syscall
mov [brk_pointer], rax mov [brk_pointer], rax
pop rax pop rax
ret ret
+219 -17
View File
@@ -1,54 +1,256 @@
%include "symbols.asm" %include "symbols.asm"
section .bss section .bss
extern gameboard_ptr extern gameboard_ptr
extern term_rows extern term_rows
extern term_cols extern term_cols
extern gameboard_size
global simulation_running
simulation_running: RESB 1
next_frame_ptr: RESQ 1
section .data section .data
extern simulation_speed
section .rodata
clear: db ESC_CHAR, "[2J", 0 clear: db ESC_CHAR, "[2J", 0
global reset
reset: db ESC_CHAR, "[0m", 0 reset: db ESC_CHAR, "[0m", 0
resetLen: equ $-reset-1
global resetLen
statusbar: db ESC_CHAR, "[100m", "Use arrow keys to move cursor, enter to invert cell, p to simulation", 0 home_cursor: db ESC_CHAR, "[H", 0
statusbar: db ESC_CHAR, "[32;100m", "Use arrow keys to move cursor, enter to invert cell j/k to change simulation speed, p to simulation. Frame Delay multiplier:", 0
statusbarLen: equ $-statusbar
START_STOP_pos: equ statusbarLen-42
start_str: db "START", 0
stop_str: db "STOP ", 0
alive_switch_statement:
dq step_simulation.die; 0
dq step_simulation.die; 1
dq step_simulation.live; 2
dq step_simulation.live; 3
dq step_simulation.die; 4
dq step_simulation.die; 5
dq step_simulation.die; 6
dq step_simulation.die; 7
dq step_simulation.die; 8
section .text section .text
extern print_str extern print_str
extern string_copy extern string_copy
extern memory_set
extern memory_copy
extern alloc
extern unsigned_int_to_ascii
global init_gameboard
init_gameboard: init_gameboard:
mov ax, [term_cols] xor rax, rax
mov cx, [term_rows] xor rcx, rcx
mul rcx
mov rdx, rax
sub rdx, rcx; get pointer to start of last line
lea rdi, [gameboard_ptr] mov rdi, [gameboard_ptr]
add rdi, rax; get end of gameboard push rdi
mov rsi, 0x20; set rsi to SPACE character
sub rdi, 5; get space for reset sequence mov rdx, [gameboard_size]
lea rsi, [reset]
push rdx push rdx
call string_copy add rdx, ESC_chars_compensation_Len; I dont know how this work but it works so i wont touch it
call memory_set
pop rdx pop rdx
mov rdi, rdx pop rdi
add rdi, rdx; get pointer to last char on screen
push rdx
push rdi
add rdi, ESC_chars_compensation_Len
lea rsi, [reset]
call string_copy
pop rdi
xor rax, rax
mov ax, [term_cols]
sub rdi, rax
lea rsi, [statusbar] lea rsi, [statusbar]
call string_copy call string_copy
pop rdi
call alloc
mov [next_frame_ptr], rax
ret ret
global print_game_ui
print_game_ui: print_game_ui:
lea rdi, [clear] lea rdi, [home_cursor]
call print_str call print_str
mov qword rdi, [gameboard_ptr]
push rdi
add rdi, [gameboard_size]
sub di, [term_cols]
push rdi
add rdi, START_STOP_pos
mov cl, [simulation_running]
test cl,cl; test if simulation is running
jz .simulation_not_running
lea rsi, [stop_str]
jmp .end_simulation_running_check
.simulation_not_running:
lea rsi, [start_str]
.end_simulation_running_check:
call string_copy
pop rdi
add rdi, statusbarLen
movss xmm0, [simulation_speed]
cvttss2si rsi, xmm0
push rsi
push rdi
call unsigned_int_to_ascii
pop rdi
add rdi, rax
mov byte [rdi], '.'
inc rdi
pop rax
cvtsi2ss xmm1, rax
subss xmm0, xmm1; get only value after decimal point
mov rax, 10
cvtsi2ss xmm1, rax
mulss xmm0, xmm1
cvttss2si rsi, xmm0; get first decimal point as int
call unsigned_int_to_ascii; rdi already set
pop rdi
call print_str
ret
%macro check_if_hashtag 2
cmp %1, r8
jl .no_count_%2
cmp %1, r9
ja .no_count_%2
mov r11b, [%1]
cmp r11b, '#'
jne .no_count_%2
inc dl
.no_count_%2:
%endmacro
global step_simulation:
step_simulation:
mov rdi, [next_frame_ptr]; destination
mov rsi, [gameboard_ptr]; source
mov rcx, [gameboard_size]; number of iterations
mov r8, rsi; store lowest address posible so we are not checking out of bounds
mov r9, rsi
add r9, rcx; store higest address posible so we are not checking out of bounds
xor r10, r10
mov r10w, [term_cols]
;mov r11, [term_rows] this register has been confiscated since i cannot use ah because of error: cannot use high byte register in rex instruction
sub rcx, r10; remove status bar
xor rax, rax; this shouldn't be needed but just to be sure
xor r11, r11
xor rdx, rdx; we will use dl as # counter
.for_every_column_on_gameboard:
xor dl, dl
mov al, [rsi]; NOTE to self if i need extra register i can shift this to ah and free up r11
inc rsi
check_if_hashtag rsi, 1; check column to the to the right
dec rsi
dec rsi
check_if_hashtag rsi, 2; check the one to the left
inc rsi
add rsi, r10
check_if_hashtag rsi, 3; check the one to the down
inc rsi
check_if_hashtag rsi, 4; check the one to the down-right
dec rsi
dec rsi
check_if_hashtag rsi, 5; check the one to the down-left
inc rsi
sub rsi, r10
sub rsi, r10
check_if_hashtag rsi, 6; check the one to the up
inc rsi
check_if_hashtag rsi, 7; check the one to the up-right
dec rsi
dec rsi
check_if_hashtag rsi, 8; check the one to the up-left
inc rsi
add rsi, r10
cmp al, '#'
jne .dead_cell
jmp [alive_switch_statement+(rdx*8)]
.die:
mov byte [rdi], 0x20; SPACE
jmp .end_check
.live:
mov byte [rdi], '#'
jmp .end_check
.dead_cell:
cmp dl, 3
jne .fill_space_there
mov byte [rdi], '#'
jmp .end_check
.fill_space_there:
mov byte [rdi], 0x20; SPACE
.end_check:
dec rcx
inc rdi
inc rsi
test rcx, rcx
jnz .for_every_column_on_gameboard
mov rsi, [next_frame_ptr]; source
mov rdi, [gameboard_ptr]; destination
mov rdx, [gameboard_size]; number of iterations
sub rdx, r10; remove statusbar
call memory_copy
ret ret
+401 -3
View File
@@ -1,12 +1,410 @@
%include "symbols.asm"
section .bss section .bss
cursor_rows: RESW 1 alignb 16
cursor_cols: RESW 1 termios: RESZ 1; 60 bytes is needed i use 64 for alligment and it is easier to work with
extern multipurpuse_buf
extern term_rows
extern term_cols
extern gameboard_ptr
extern simulation_running
extern running_in_tty
section .data
cursor_rows: dw 1
cursor_cols: dw 1
global simulation_speed
simulation_speed dd 1.0
section .rodata
extern reset
cursor_up: db ESC_CHAR, "[1A", 0
cursor_down: db ESC_CHAR, "[1B", 0
cursor_right: db ESC_CHAR, "[1C", 0
cursor_left: db ESC_CHAR, "[1D", 0
cursor_color: db ESC_CHAR, "[45m", 0
speed_multiplier dd 50.0
arrow_switch_statement:
dq handle_user_input.arrow_up
dq handle_user_input.arrow_down
dq handle_user_input.arrow_right
dq handle_user_input.arrow_left
section .text section .text
extern print_str
extern step_simulation
extern unsigned_int_to_ascii
extern print_game_ui
extern string_copy
global handle_user_input global handle_user_input
handle_user_input: handle_user_input:; main loop of the program
push r12
push r13
push r14
lea r12, [multipurpuse_buf]
.main_loop:
xor r13, r13
; put the cursor where it should be
call print_cursor
xor rax, rax
mov qword [r12], rax; zeroout the buffer
mov rax, SYS_POLL
mov dword [r12], STDIN; create pollfd struct
mov word [r12+4], POLLIN
mov rdi, r12
mov rsi, 1; only one file descriptor is provided
movss xmm0, [speed_multiplier]
movss xmm1, [simulation_speed]
mulss xmm0, xmm1; callculate sleep lenght
cvttss2si rdx, xmm0; truncate and copy to rdx
mov r14, rdx
syscall
mov sil, [running_in_tty]
test sil, sil
jz .skip_tty_mul
push rax
mov rax, 2500; magic number
xor rdx,rdx
mul r14
mov r14, rax
pop rax
.skip_tty_mul:
test rax, rax; SYS_POLL returns 0 when no change happens within timeout
jz .no_input
.repeat_read:
xor rax, rax
mov qword [r12], rax; zeroout the buffer
mov rax, SYS_READ
mov rdi, STDIN
lea rsi, [r12]
mov rdx, 8; size of multipurpuse buffer
syscall; read user input
cmp rax, EAGAIN
jne .handle_input
mov al, [running_in_tty]
test al, al
jz .no_input
; this runs only if running in tty
test r14, r14
jz .no_input; timeout
dec r14
jmp .repeat_read
.handle_input:
mov rax, [r12]
cmp eax, 0x00415B1B; check if input is more than left arrow
jl .handle_single_byte_chars
bswap eax
sub eax, 0x1B5B4100
shr eax, 8
cmp al, 3
ja .no_input
mov r9w, [term_rows]
dec r9w
mov r10w, [term_cols]
jmp [arrow_switch_statement+(rax*8)]; lets hope this works
.arrow_up:
dec word [cursor_rows]
jnz .move_cursor_up
inc word [cursor_rows]
jmp .end_input_handling
.move_cursor_up:
lea rdi, [cursor_up]
call print_str
jmp .end_input_handling
.arrow_down:
mov r8w, [cursor_rows]
inc r8w
cmp word r8w, r9w
ja .end_input_handling
mov word [cursor_rows], r8w
lea rdi, [cursor_down]
call print_str
jmp .end_input_handling
.arrow_right:
mov r8w, [cursor_cols]
inc r8w
cmp word r8w, r10w
ja .end_input_handling
mov word [cursor_cols], r8w
lea rdi, [cursor_right]
call print_str
jmp .end_input_handling
.arrow_left:
dec word [cursor_cols]
jnz .move_cursor_left
inc word [cursor_cols]
jmp .end_input_handling
.move_cursor_left:
lea rdi, [cursor_left]
call print_str
jmp .end_input_handling
.handle_single_byte_chars:
cmp al, 0xa; NEWLINE (enter key)
jne .check_p
xor rax, rax; zeroout rax
mov ax, [cursor_rows]
dec ax
mul word [term_cols]
mov cx, [cursor_cols]
dec cx
add ax, cx
mov rdi, [gameboard_ptr]
add rdi, rax
mov cl, [rdi]
cmp cl, '#'
je .hashtag_present
mov byte [rdi], '#'
jmp .end_input_handling
.hashtag_present:
mov byte [rdi], ' '
jmp .end_input_handling
.check_p:
cmp al, 'p'
jne .check_j
xor byte [simulation_running], 0x01; switch simulation on or off
jmp .end_input_handling
.check_j:
cmp al, 'j'
jne .check_k
movss xmm0, [simulation_speed]
mov eax, 0x3DCCCCCD; 0.1f
vmovd xmm1, eax
addss xmm0, xmm1
; wont check for overflows since the user would need be crazy to reach that number
movss [simulation_speed], xmm0
jmp .end_input_handling
.check_k:
cmp al, 'k'
jne .check_q
movss xmm0, [simulation_speed]
mov eax, 0x3DCCCCCD; 0.1f
vmovd xmm1, eax
subss xmm0, xmm1
ucomiss xmm0, xmm1; check if number is smaller than 0.1
jb .end_input_handling
movss [simulation_speed], xmm0
jmp .end_input_handling
.check_q:
cmp al, 'q'
jne .end_input_handling
jmp .function_exit
ret; exit if q pressed
.end_input_handling:
mov r13b, 1
.no_input:
mov al, [simulation_running]
test al, al
jz .dont_step
call step_simulation
mov r13b, 1
.dont_step:
test r13b, r13b
jz .main_loop
call print_game_ui
jmp .main_loop
.function_exit:
pop r14
pop r13
pop r12
ret
global disable_canonical_mode_and_echo
disable_canonical_mode_and_echo:
mov rax, SYS_IOCTL
mov rdi, STDIN
mov rsi, TCGETS
lea rdx, [termios]
syscall
; save original termios struct
%ifdef AVX2
%ifdef AVX512
vmovdqa64 zmm0, [termios]
%else
vmovdqa ymm0, [termios]
vmovdqa ymm1, [termios+32]
%endif
%else
vmovdqa xmm0, [termios]
vmovdqa xmm1, [termios+16]
vmovdqa xmm2, [termios+32]
vmovdqa xmm3, [termios+64]
%endif
mov eax, [termios+12]; get c_lflag
and eax, NOT_ECHO; disable ECHO
and eax, NOT_ICANON; disable ICANON
mov [termios+12], eax
mov rax, SYS_IOCTL
mov rdi, STDIN
mov rsi, TCSETS
lea rdx, [termios]
syscall
; load original termios struct
%ifdef AVX2
%ifdef AVX512
vmovdqa64 [termios], zmm0
%else
vmovdqa [termios], ymm0
vmovdqa [termios+32], ymm1
%endif
%else
vmovdqa [termios], xmm0
vmovdqa [termios+16], xmm1
vmovdqa [termios+32], xmm2
vmovdqa [termios+64], xmm3
%endif
ret
global reset_terminal
reset_terminal:
mov rax, SYS_IOCTL
mov rdi, STDIN
mov rsi, TCSETS
lea rdx, [termios]
syscall
ret
print_cursor:
push r12
push r13
lea r12, [multipurpuse_buf]
mov rdi, r12
mov word [rdi], 0x5B1B; will store ESC_CHAR, '[' they have to be in reverse order here due to little endian
add rdi, 2
push rdi
xor rsi, rsi
mov si, [cursor_rows]
call unsigned_int_to_ascii
pop rdi
add rdi, rax; add lenght of string to pointer
mov byte [rdi], ';'
inc rdi
push rdi
mov si, [cursor_cols]
call unsigned_int_to_ascii
pop rdi
add rdi, rax
mov byte [rdi], 'H'
inc rdi
mov byte [rdi], 0; null terminate
mov rdi, r12
call print_str
; write there real cursor
xor r13, r13
mov rdi, r12
lea rsi, [cursor_color]
call string_copy
mov rdi, r12
add r13, rax
add rdi, r13
xor rax, rax
mov ax, [cursor_rows]
dec ax
mul word [term_cols]; get index of character
add ax, [cursor_cols]
dec ax
xor rsi, rsi
add rax, [gameboard_ptr]
mov sil, [rax]; now we got the character in si
mov byte [rdi], sil
inc rdi
inc r13
lea rsi, [reset]
call string_copy
mov rdi, r12
add r13, rax
add rdi, r13
lea rsi, [cursor_left]
call string_copy
mov rdi, r12
add r13, rax
add rdi, r13
inc rdi
mov byte [rdi], 0; null terminate
mov rdi, r12
call print_str
pop r13
pop r12
ret
+101 -6
View File
@@ -1,24 +1,50 @@
%include "symbols.asm" %include "symbols.asm"
section .bss section .bss
multipurpuse_buf: RESB 8 global multipurpuse_buf
multipurpuse_buf: RESB 16
global term_rows
term_rows: RESW 1 term_rows: RESW 1
global term_cols
term_cols: RESW 1 term_cols: RESW 1
global gameboard_ptr
gameboard_ptr: RESQ 1 gameboard_ptr: RESQ 1
global gameboard_size
gameboard_size: RESQ 1
extern cursor_rows extern cursor_rows
extern cursor_cols extern cursor_cols
section .data
global running_in_tty
running_in_tty: RESB 1
section .rodata
extern resetLen
hide_cursor: db ESC_CHAR, "[?25l", 0
show_cursor: db ESC_CHAR, "[?25h", 0
help_text: db "asm-game-of-life [args]",0xA,"-h display this help menu",0xA,"Controls:",0xA,"use arrow keys to move around",0xA,"ENTER to invert cell",0xA,"p to START/STOP simulation",0xA,"k to increase simulation speed",0xA,"j to decrese simulation speed",0xA, 0
section .text section .text
extern print_str extern print_str
extern unsigned_int_to_ascii extern unsigned_int_to_ascii
extern init_alloc extern init_alloc
extern alloc extern alloc
extern init_gameboard
extern print_game_ui
extern handle_user_input
extern disable_canonical_mode_and_echo
extern reset_terminal
global _start global _start
_start: _start:
; get terminal dimensions ; get terminal dimensions
@@ -36,23 +62,92 @@ _start:
; handle args ; handle args
pop rcx; get argc (number of arguments) pop rcx; get argc (number of arguments)
pop rax; get rid of program name arugument
cmp rcx, 1 cmp rcx, 1
jle .no_arguments_provided jle .no_arguments_provided
; TODO hanndle arguments dec rcx
.handle_arg:
pop rax
mov word di, [rax]
cmp di, 0x682D; check if -h was passed
jne .next_arg
lea rdi, [help_text]
call print_str
jmp .exit_program
.next_arg:
dec rcx
test rcx, rcx
jnz .handle_arg
.no_arguments_provided: .no_arguments_provided:
pop rax; get rid of null termination of argv
; handle enviroment vars
.handle_env:
pop rax
test rax, rax; test if we reached end of envs
jz .no_envs
mov dword edi, [rax]
cmp edi, 0x4D524554; check for "TERM" inverted becose endiannes
jne .handle_env
mov qword rdi, [rax+5]; remove the TERM= part this should never segfault since there sould allwas be other data behind enviroment vars and i dont mind garbage
mov rsi, 0xffffffffff
and rdi, rsi
mov rsi, 0x78756e696c
cmp rdi, rsi; check for "linux"
jne .no_envs
mov byte [running_in_tty], 1
.no_envs:
call init_alloc call init_alloc
xor rax, rax
xor rcx, rcx
mov ax, [term_rows] mov ax, [term_rows]
mov cx, [term_cols] mov cx, [term_cols]
mul rcx mul rcx
mov rdi, rax mov rdi, rax
mov qword [gameboard_size], rax
inc rdi; addition byte for NULL BYTE
lea rax, [resetLen]
add rdi, rax
add rdi, ESC_chars_compensation_Len
call alloc call alloc
mov [gameboard_ptr], rax; stores pointer to gameboard array mov [gameboard_ptr], rax; stores pointer to gameboard array
call init_gameboard
; make stdin non-blocking in case polling somehow fails, or am i stupid
mov rax, SYS_FCNTL
mov rdi, STDIN
mov rsi, F_SETFL
mov rdx, O_NONBLOCK
syscall
lea rdi, [hide_cursor]
call print_str
call print_game_ui
call disable_canonical_mode_and_echo
call print_game_ui
call handle_user_input
call reset_terminal
lea rdi, [show_cursor]
call print_str
.exit_program:
mov rax, SYS_EXIT mov rax, SYS_EXIT
mov rdi, 0 ; return code mov rdi, 0 ; return code
syscall syscall
+102 -7
View File
@@ -24,7 +24,7 @@ print_str: ; takes pointer to string in rdi and retuns in rax
ret ret
global unsigned_int_to_ascii global unsigned_int_to_ascii
unsigned_int_to_ascii: ; takes pointer to array in rdi and value stored in rsi DOES NOT BOUNDS CHECK unsigned_int_to_ascii: ; takes pointer to array in rdi and value stored in rsi DOES NOT BOUNDS CHECK return len of string in rax
xor r11, r11 xor r11, r11
mov rcx, 10 mov rcx, 10
mov rax, rsi mov rax, rsi
@@ -60,15 +60,110 @@ unsigned_int_to_ascii: ; takes pointer to array in rdi and value stored in rsi D
ret ret
string_copy:; takes pointer to destination in rdi and pointer to source in rsi global string_copy
string_copy:; takes pointer to destination in rdi and pointer to source in rsi and return lenght in rax
xor rax, rax xor rax, rax
xor rcx, rcx
.copy_next_byte: .copy_next_byte:
mov byte al, [rdi+rax] mov byte cl, [rsi+rax]
mov [rsi+rax], al test cl, cl
jz .exit
mov [rdi+rax], cl
inc rax inc rax
test rax,rax jmp .copy_next_byte
jnz .copy_next_byte
.exit:
ret ret
global memory_set:
memory_set:; takes destination in rdi, byte in sil and lenght in rdx
; first check if value is 16 byte alligned
mov r9, rdi; move destination to r9
mov r11, 0x0101010101010101; to extend across whoule register
movzx rsi, sil
imul r11, rsi; to extend across whoule register
cmp rdx, 16
jnl .write_16_or_more_bytes
mov rcx, rdx
jmp .write_less_than_16_bytes
.write_16_or_more_bytes:
mov rax, rdi; move destination to rax
and rax, 0xF; offset is stored in rax
test al, al; check if resault is 0
jz .addr_is_16_Byte_alligned
mov cl, 16
sub cl, al; now offset to first higher 16 byte alligned address is stored in r8
movzx rcx, cl; remove ani posible garbage
.write_less_than_16_bytes:
mov rax, r11
sub rdx, rcx; we will write these bytes now
rep stosb
.addr_is_16_Byte_alligned:
mov r10, rdx
shr r10, 4; set it to how many 128bit(16Byte) chunk we need
test r10, r10; check if we need to write aditional 16 bytes at all
jz .function_exit
%ifdef AVX512
vpbroadcastq xmm8, r11
%else
movq xmm8, r11
shufpd xmm8, xmm8, 0x00
%endif
.move_16_bytes:
movdqa [rdi], xmm8
add rdi, 16
sub rdx, 16
cmp rdx, 16; test if rdx is less than 16
jge .move_16_bytes
.function_exit:
test rdx, rdx; test if rdx is 0
jz .true_function_exit
mov cl, dl
jmp .write_less_than_16_bytes
.true_function_exit:
mov rax, r9; return pointer to memory area same as memset in libc
ret
global memory_copy:
memory_copy:; takes destination in rdi, source in rsi and lenght in rdx
; first check if value is 16 byte alligned
mov r9, rdi
mov rcx, rdx
shr rcx, 3; calculate how many 8 byte chunks we need
and rdx, 0x7; calculate the reminder
rep movsq; move as many 8 byte chunks as posible
mov rcx, rdx
rep movsb; move the rest
mov rax, r9; return pointer to memory area same as memcpy in libc
ret
+18
View File
@@ -1,10 +1,28 @@
SYS_EXIT equ 60 SYS_EXIT equ 60
SYS_IOCTL equ 16 SYS_IOCTL equ 16
SYS_READ equ 0
SYS_WRITE equ 1 SYS_WRITE equ 1
SYS_BRK equ 12 SYS_BRK equ 12
SYS_FCNTL equ 72
SYS_POLL equ 7
SYS_NANOSLEEP equ 35
STDIN equ 0
STDOUT equ 1 STDOUT equ 1
TIOCGWINSZ equ 0x5413 TIOCGWINSZ equ 0x5413
TCGETS equ 0x5401
TCSETS equ 0x5402
F_SETFL equ 4
O_NONBLOCK equ 2048
POLLIN equ 0x0100; compensate for litle endian
NOT_ECHO equ -9
NOT_ICANON equ -3
EAGAIN equ -11
ASCII_ZERO equ 48 ASCII_ZERO equ 48
ESC_CHAR equ 27 ESC_CHAR equ 27
ESC_chars_compensation_Len equ 9; i have to compensate for escape sequences that dont get printed why 11 exactly, I dont know