Compare commits

...

2 Commits

Author SHA1 Message Date
fa7b4c70b8 IT WORKS 2025-07-12 16:09:39 +02:00
a46f907ff6 fixing segfault and such 2025-07-12 11:47:57 +02:00
6 changed files with 294 additions and 103 deletions

View File

@ -8,6 +8,11 @@ DEBUG_LD_FLAGS := -g
DEBUG_NASM_FLAGS := -g -F dwarf DEBUG_NASM_FLAGS := -g -F dwarf
# check for avx2 support # 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) ifeq ($(shell grep -o 'avx512[^ ]*' /proc/cpuinfo | head -n 1),avx512)
NASM_FLAGS += -DAVX512 NASM_FLAGS += -DAVX512
endif endif

View File

@ -23,17 +23,30 @@ section .rodata
home_cursor: db ESC_CHAR, "[H", 0 home_cursor: db ESC_CHAR, "[H", 0
statusbar: db ESC_CHAR, "[30;100m", "Use arrow keys to move cursor, enter to invert cell j/k to change simulation speed, p to simulation", 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", 0
START_STOP_pos: equ $-statusbar-17 START_STOP_pos: equ $-statusbar-17
start_str: db "START", 0 start_str: db "START", 0
stop_str: db "STOP ", 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_set
extern memory_copy
extern alloc extern alloc
global init_gameboard global init_gameboard
@ -99,69 +112,111 @@ print_game_ui:
ret ret
%macro check_if_hashtag 1 %macro check_if_hashtag 2
cmp r8, %1 cmp %1, r8
jl +7 jl .no_count_%2
cmp r9, %1 cmp %1, r9
ja +5 ja .no_count_%2
mov r11b, [%1] mov r11b, [%1]
cmp r11b, '#' cmp r11b, '#'
jne +2 jne .no_count_%2
inc dl inc dl
.no_count_%2:
%endmacro %endmacro
global step_simulation: global step_simulation:
step_simultion: step_simulation:
mov rdi, [next_frame_ptr]; destination mov rdi, [next_frame_ptr]; destination
mov rsi, [gameboard_ptr]; source mov rsi, [gameboard_ptr]; source
mov rcx, [gameboard_size]; number of iterations mov rcx, [gameboard_size]; number of iterations
mov r8, rsi; store lowest address posible so we are not checking out of bounds mov r8, rsi; store lowest address posible so we are not checking out of bounds
mov r9, rsi mov r9, rsi
add r9, rcx; store higest address posible so we are not checking out of bounds add r9, rcx; store higest address posible so we are not checking out of bounds
mov r10, [term_cols] 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 ;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 rax, rax; this shouldn't be needed but just to be sure
xor r11, r11 xor r11, r11
xor rdx, rdx; we will use dl as # counter xor rdx, rdx; we will use dl as # counter
.for_every_column_on_gameboard: .for_every_column_on_gameboard:
mov al, [rdi]; NOTE to self if i need extra register i can shift this to ah and free up r11 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 rdi inc rsi
check_if_hashtag rdi check_if_hashtag rsi, 1; check column to the to the right
dec rdi dec rsi
check_if_hashtag rdi-1 dec rsi
check_if_hashtag rsi, 2; check the one to the left
inc rsi
add rsi, r10
add rdi, r10
check_if_hashtag rdi 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 rdi
check_if_hashtag rdi inc rsi
dec rdi test rcx, rcx
jnz .for_every_column_on_gameboard
check_if_hashtag rdi-1 mov rsi, [next_frame_ptr]; source
mov rdi, [gameboard_ptr]; destination
mov rdx, [gameboard_size]; number of iterations
sub rdx, r10; remove statusbar
sub rdi, r10 call memory_copy
sub rdi, r10
check_if_hashtag rdi
inc rdi
check_if_hashtag rdi
dec rdi
check_if_hashtag rdi-1
add rdi, r10
; TODO create jump table
ret ret

View File

@ -1,8 +1,8 @@
%include "symbols.asm" %include "symbols.asm"
section .bss section .bss
cursor_rows: RESW 1; TODO DONT FORGET TO INICIALIZE 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 multipurpuse_buf
@ -12,13 +12,16 @@ section .bss
extern gameboard_ptr extern gameboard_ptr
extern simulation_running extern simulation_running
section .data
cursor_rows: dw 1
cursor_cols: dw 1
section .rodata section .rodata
cursor_up: db ESC_CHAR, "[1A", 0 cursor_up: db ESC_CHAR, "[1A", 0
cursor_down: db ESC_CHAR, "[1B", 0 cursor_down: db ESC_CHAR, "[1B", 0
cursor_right: db ESC_CHAR, "[1C", 0 cursor_right: db ESC_CHAR, "[1C", 0
cursor_left: db ESC_CHAR, "[1D", 0 cursor_left: db ESC_CHAR, "[1D", 0
arrow_switch_statement: arrow_switch_statement:
@ -30,73 +33,144 @@ section .rodata
section .text section .text
extern print_str extern print_str
extern step_simulation
extern unsigned_int_to_ascii
extern print_game_ui
global handle_user_input global handle_user_input
handle_user_input:; main loop of the program handle_user_input:; main loop of the program
push r12
lea r12, [multipurpuse_buf]
.main_loop: .main_loop:
; put the cursor where it should be
mov rdi, r12; multipurpuse_buf pointer is in 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; multipurpuse_buf pointer is in r12
call print_str
xor rax, rax xor rax, rax
mov qword [multipurpuse_buf], rax; zeroout the buffer mov qword [r12], rax; zeroout the buffer
mov rax, SYS_POLL mov rax, SYS_POLL
mov rdi, STDIN mov dword [r12], STDIN; create pollfd struct
mov word [r12+4], POLLIN
mov rdi, r12
mov rsi, 1; only one file descriptor is provided mov rsi, 1; only one file descriptor is provided
mov rdx, 0; no timeout. maybe use this for final sleep but run if user inputs something TODO mov rdx, 500; no timeout. maybe use this for final sleep but run if user inputs something TODO
syscall syscall
test rax, rax; SYS_POLL returns 0 when no change happens within timeout test rax, rax; SYS_POLL returns 0 when no change happens within timeout
jz .no_input jz .no_input
xor rax, rax
mov qword [r12], rax; zeroout the buffer
mov rax, SYS_READ mov rax, SYS_READ
mov rdi, STDIN mov rdi, STDIN
lea rsi, [multipurpuse_buf] lea rsi, [r12]
mov rdx, 8; size of multipurpuse buffer mov rdx, 8; size of multipurpuse buffer
syscall; read user input syscall; read user input
mov rax, [multipurpuse_buf] cmp rax, EAGAIN
shr rax, 5; we need only 3 bytes for this inpus sceame je .no_input
cmp eax, 0x001B5B44; check if input is more than left arrow mov rax, [r12]
ja .handle_single_byte_chars
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]
sub eax, 0x1B5B41
jmp [arrow_switch_statement+(rax*8)]; lets hope this works jmp [arrow_switch_statement+(rax*8)]; lets hope this works
.arrow_up: .arrow_up:
dec word [cursor_rows] dec word [cursor_rows]
jnz .move_cursor_up
inc word [cursor_rows]
jmp .no_input
.move_cursor_up:
lea rdi, [cursor_up] lea rdi, [cursor_up]
call print_str call print_str
jmp .no_input jmp .no_input
.arrow_down: .arrow_down:
inc word [cursor_rows] mov r8w, [cursor_rows]
inc r8w
cmp word r8w, r9w
ja .no_input
mov word [cursor_rows], r8w
lea rdi, [cursor_down] lea rdi, [cursor_down]
call print_str call print_str
jmp .no_input jmp .no_input
.arrow_right: .arrow_right:
inc word [cursor_cols] mov r8w, [cursor_cols]
inc r8w
cmp word r8w, r10w
ja .no_input
mov word [cursor_cols], r8w
lea rdi, [cursor_right] lea rdi, [cursor_right]
call print_str call print_str
jmp .no_input jmp .no_input
.arrow_left: .arrow_left:
dec word [cursor_cols] dec word [cursor_cols]
jnz .move_cursor_left
inc word [cursor_cols]
jmp .no_input
.move_cursor_left:
lea rdi, [cursor_left] lea rdi, [cursor_left]
call print_str call print_str
jmp .no_input jmp .no_input
.handle_single_byte_chars: .handle_single_byte_chars:
shr eax, 2; get the char to al
cmp al, 0xa; NEWLINE (enter key) cmp al, 0xa; NEWLINE (enter key)
jne .check_p jne .check_p
xor rax, rax; zeroout rax xor rax, rax; zeroout rax
mov ax, [cursor_rows] mov ax, [cursor_rows]
mul dword [term_cols] dec ax
add rax, [cursor_cols] mul word [term_cols]
mov cx, [cursor_cols]
dec cx
add ax, cx
lea rdi, [gameboard_ptr+rax] mov rdi, [gameboard_ptr]
add rdi, rax
mov cl, [rdi] mov cl, [rdi]
cmp cl, '#' cmp cl, '#'
je .hashtag_present je .hashtag_present
@ -127,15 +201,92 @@ handle_user_input:; main loop of the program
.check_k: .check_k:
cmp al, 'k' cmp al, 'k'
jne .no_input jne .check_q
; TODO implement simulation speed ; TODO implement simulation speed
.check_q:
cmp al, 'q'
jne .no_input
pop r12
ret; exit if q pressed
.no_input: .no_input:
mov al, [simulation_running]
test al, al
jz .dont_step
call step_simulation
.dont_step:
call print_game_ui
jmp .main_loop jmp .main_loop
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 ret

View File

@ -33,6 +33,11 @@ extern alloc
extern init_gameboard extern init_gameboard
extern print_game_ui 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
@ -82,7 +87,11 @@ _start:
call print_game_ui call print_game_ui
call disable_canonical_mode_and_echo
call handle_user_input
call reset_terminal

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
@ -154,52 +154,16 @@ memory_copy:; takes destination in rdi, source in rsi and lenght in rdx
mov r9, rdi mov r9, rdi
cmp rdx, 16 mov rcx, rdx
jnl .write_16_or_more_bytes shr rcx, 3; calculate how many 8 byte chunks we need
mov rcx, rdx and rdx, 0x7; calculate the reminder
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
rep movsq; move as many 8 byte chunks as posible
test al, al; check if resault is 0
jz .addr_is_16_Byte_alligned
mov cl, 16 mov rcx, rdx
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: rep movsb; move the rest
sub rdx, rcx; we will write these bytes now
rep movsb
.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
.move_16_bytes:
movdqa xmm8, [rsi]
movdqa [rdi], xmm8
add rdi, 16
add rsi, 16
sub rdx, 16
cmp rdx, 16; test if rdx is less than 16 mov rax, r9; return pointer to memory area same as memcpy in libc
jge .move_16_bytes
.function_exit:
test rdx, rdx; test if rdx is 0
jz .true_function_exit
movzx rcx, dl
jmp .write_less_than_16_bytes
.true_function_exit:
mov rax, r9; return pointer to memory area same as memset in libc
ret ret

View File

@ -10,9 +10,16 @@ STDIN equ 0
STDOUT equ 1 STDOUT equ 1
TIOCGWINSZ equ 0x5413 TIOCGWINSZ equ 0x5413
POLLIN equ 1 TCGETS equ 0x5401
TCSETS equ 0x5402
F_SETFL equ 4 F_SETFL equ 4
O_NONBLOCK equ 2048 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