игра в жизнь на ассемблере fasm. ошибка

два файла main.asm


include "logic.asm"

section '.data' writable
    grid db 0,0,0,0,0
         db 0,0,1,0,0
         db 0,0,0,1,0
         db 0,1,1,1,0
         db 0,0,0,0,0
    public grid
    grid_size = 5
    public grid_size

    new_grid db grid_size*grid_size dup(0) 
    msg db "Generation: ", 0

    alive_cell db "1 ", 0
    dead_cell db "0 ", 0
    newline db 10, 0
    neighbor_count db '0', 0

    birth_rule      db 3    ; Birth rule
    survive_min     db 2    ; Survival minimum
    survive_max     db 5    ; Survival maximum


    max_iterations db 2  ; Number of generations to simulate

section '.text' executable
public _start

_start:
    movzx r12, byte [max_iterations]  
    ;call print_grid_with_generation
    .main_loop:
        call print_grid_with_generation

        ; Process the grid
        mov rsi, grid
        mov rdi, new_grid
        mov rcx, grid_size * grid_size 
        call process_grid 

        ; Copy new_grid back to grid
        mov rcx, grid_size * grid_size
        lea rsi, [new_grid]
        lea rdi, [grid]
        rep movsb

        ; Decrement counter and check
        dec r12
        jz .exit
    jmp .main_loop
    .exit:
        mov rax, 60         ; sys_exit
        xor rdi, rdi        ; exit code 0
        syscall

и файл logic.asm

    new_line:
    push rax
    push rdi
    push rsi
    push rdx
    push rcx
    mov rax, 0xA
    push rax
    mov rdi, 1
    mov rsi, rsp
    mov rdx, 1
    mov rax, 1
    syscall
    pop rax
    pop rcx
    pop rdx
    pop rsi
    pop rdi
    pop rax
    ret


print_grid_with_generation:
    push rax
    push rdi
    push rsi
    push rdx
    push r12
    
    ; Calculate generation number
    mov al, [max_iterations]
    sub al, r12b
    add al, '0'
    mov [msg+11], al    ; Update digit in message
    
    ; Print generation header
    mov rax, 1
    mov rdi, 1
    lea rsi, [msg]
    mov rdx, 13        ; Length of "Generation: X" + newline
    syscall
    call new_line
    
    ; Print the grid
    call print_grid
    call new_line
    pop r12
    pop rdx
    pop rsi
    pop rdi
    pop rax
    ret


print_grid:
    push rax
    push rbx
    push rcx
    push rdx
    push rsi
    push rdi
    
    mov rsi, grid      ; Указатель на начало сетки
    mov rbx, grid_size  ; Счетчик строк
    
    .row_loop:
        mov rcx, grid_size  ; Счетчик столбцов
        push rsi            ; Сохраняем начало строки
        
    .col_loop:
        ; Загружаем значение клетки
        mov al, [rsi]
        
        ; Выбираем строку для вывода
        mov rdx, 2          ; Длина вывода (2 символа)
        lea rdi, [dead_cell] ; По умолчанию мертвая клетка
        cmp al, 0
        jz .print
        lea rdi, [alive_cell] ; Живая клетка
        
    .print:
        ; Выводим клетку
        push rcx
        push rsi
        mov rax, 1          ; sys_write
        mov rsi, rdi        ; Указатель на строку "0 " или "1 "
        mov rdi, 1          ; stdout
        syscall
        pop rsi
        pop rcx
        
        ; Переходим к следующей клетке
        inc rsi
        dec rcx
        jnz .col_loop
        
        ; Переход на новую строку
        push rsi
        mov rax, 1          ; sys_write
        mov rdi, 1          ; stdout
        lea rsi, [newline]
        mov rdx, 1          ; Длина
        syscall
        pop rsi
        
        pop rsi             ; Восстанавливаем начало строки
        add rsi, grid_size  ; Переходим к следующей строке
        dec rbx
        jnz .row_loop
        
        pop rdi
        pop rsi
        pop rdx
        pop rcx
        pop rbx
        pop rax
        ret


;---[process_grid]---
; Вход: rSI=grid, rDI=new_grid, rCX=size
process_grid:
  push rax
  push rcx 
  push rbx
  push r12
  xor rbx, rbx            ; Индекс клетки (0..size*size-1)
  mov rcx, grid_size * grid_size
    .cell_loop:
        mov rax, rbx
        call count_neighbors    ; EDX = кол-во соседей
        mov al, [rsi + rbx]    ; Текущее состояние
        call update_cell        ; AL = новое состояние
        mov [rdi + rbx], al    ; Сохраняем в new_grid
        inc rbx
        cmp rbx, rcx
    jne .cell_loop
        pop r12
        pop rbx
        pop rcx
        pop rax
    ret



;---[update_cell]---
; Вход: AL = текущее состояние (0 или 1)
;       DL = число живых соседей
; Выход: AL = новое состояние (0 или 1)

update_cell:
    cmp al, 1
    je .check_survival

    ; Клетка мертва → проверяем рождение
    cmp dl, [birth_rule]
    jne .stay_dead

    ; Рождение!
    mov al, 1
    jmp .done

    .stay_dead:
        xor al, al
        jmp .done


    .check_survival:
        ; Живая клетка → проверяем условия выживания
        cmp dl, [survive_min]
        jl .die
        cmp dl, [survive_max]
        jg .die
        ; В пределах → продолжает жить
        mov al, 1
        jmp .done

    .die:
        xor al, al   ; Умирает

    .done:
        ret




;---[count_neighbors]---
; Вход: ESI = grid, EDI = index, ECX = size
; Выход: DL = кол-во живых соседей (0..8)

count_neighbors:
    push rcx
    push rdi
    push rdx
    push rbx
    push r8
    push r9
    push r10
    push r11
    push r12

    xor dl, dl        ; Счётчик соседей

    mov rbx, rdi      ; сохраняем index
    xor rdx, rdx
    mov rax, rbx
    mov ecx, grid_size
    div ecx           ; RAX = Y, RDX = X
    mov r11d, eax     ; Y
    mov r12d, edx     ; X

    ; DL = счётчик живых соседей
    xor dl, dl

    ; Сосед (x-1, y-1)
    mov eax, r12d      ; X
    add eax, -1
    mov ebx, r11d      ; Y
    add ebx, -1
    call check_bounds_and_alive

    ; Сосед (x, y-1)
    mov eax, r12d
    mov ebx, r11d
    add ebx, -1
    call check_bounds_and_alive

    ; Сосед (x+1, y-1)
    mov eax, r12d
    add eax, +1
    mov ebx, r11d
    add ebx, -1
    call check_bounds_and_alive

    ; Сосед (x-1, y)
    mov eax, r12d
    add eax, -1
    mov ebx, r11d
    call check_bounds_and_alive

    ; Сосед (x+1, y)
    mov eax, r12d
    add eax, +1
    mov ebx, r11d
    call check_bounds_and_alive

    ; Сосед (x-1, y+1)
    mov eax, r12d
    add eax, -1
    mov ebx, r11d
    add ebx, +1
    call check_bounds_and_alive

    ; Сосед (x, y+1)
    mov eax, r12d
    mov ebx, r11d
    add ebx, +1
    call check_bounds_and_alive

    ; Сосед (x+1, y+1)
    mov eax, r12d
    add eax, +1
    mov ebx, r11d
    add ebx, +1
    call check_bounds_and_alive

    mov rcx, grid_size * grid_size
    pop r12
    pop r11
    pop r10
    pop r9
    pop r8
    pop rbx
    pop rdx
    pop rdi
    pop rcx
    ret



check_bounds_and_alive:
    push rax
    push rbx

    ; Проверяем x < 0 или x >= grid_size
    cmp eax, 0
    jl .skip
    cmp eax, grid_size - 1
    jg .skip

    ; Проверяем y < 0 или y >= grid_size
    cmp ebx, 0
    jl .skip
    cmp ebx, grid_size - 1
    jg .skip

    ; Индекс = y * grid_size + x
    mov ecx, grid_size
    imul ebx, ecx
    add ebx, eax
    cdqe
    cmp byte [rsi + rax], 1
    jne .skip
    inc dl   ; Увеличиваем счётчик живых соседей

    .skip:
    pop rbx
    pop rax
    ret

Пример вывода:
Generation:0
0 0 0 0 0 
0 0 1 0 0 
0 0 0 1 0 
0 1 1 1 0 
0 0 0 0 0 

Generation:1
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0 

С первого же поколения он умирает, хотя по правилам не должен. Вроде ошибки в самом выводе нету.


Ответы (0 шт):