Игра в змею и использование стеков

# #assembly #x86 #nested #stack #procedure

Вопрос:

Я придумал игру в змею на уроке. Вчера мы узнали, как использовать сегмент стека (pushamp;pop) и черный бокс.Я пытался использовать его на своей змейке, но он стал длиннее и перестал работать. Может ли кто-нибудь помочь мне определить проблему? Тич сказал, что любой процесс. должно начинаться с push и заканчиваться pop, но когда я вызываю другой процесс. внутри должно быть то же самое, или я должен выскочить, прежде чем вызывать следующий процесс.? и как мне убедиться, какая часть неверна? В DOSBOX написано 0 предупреждений и 0 ошибок, но когда я играю, змея не движется, а случайный объект не появляется.

код добавлен ниже:

          MODEL small
         STACK 100h
         DATASEG
snake_length dw 3
object dw ?
Clock equ es:6Ch
message db 'game over, do you want to play again


Комментарии:

1. Push в основном выводит текущее состояние (вероятно, содержимое некоторых регистров) в верхнюю часть стека. Pop восстанавливает состояния, открывая верхнюю часть стека. Если вы хотите вызвать одну процедуру P2 из другой P1, то не нужно вызывать pop перед вызовом P2, скорее вы можете просто вызвать push в начале процедуры и pop в конце процедуры. В промежутке между нажатием и щелчком может быть тело, которое также может вызывать другие процедуры.

2. Одна из проблем, которую я вижу, заключается в том, что в "задержке" у вас есть " ret " перед всплывающими окнами - это приведет к дисбалансу стека.

3. Так много вещей не так с этой программой. На то, чтобы просмотреть это, уйдет несколько часов! Пожалуйста, ответьте на этот вопрос: до того, как вы применили " push вверху и pop внизу" , программа работала или нет?

4. Один подарок: Clock equ es:6Ch Счетчик часов BIOS находится по линейному адресу 046Ch, поэтому это приравнивание будет полезно только в том случае, если регистр ES сегмента был предварительно загружен 0040h, прежде чем пытаться прочитать часы с помощью такой инструкции mov ax, [Clock] . Проверьте, так ли это в вашем коде... Предупреждение о спойлере: это не так!

5.@kiner_shah Я полностью понимаю, что вы говорите в своем комментарии, но я боюсь, что неудачный выбор слов еще больше запутает ОП. "... не нужно звонить pop перед вызовом P2, но вы можете просто позвонить push ..." Если бы вы написали "... не нужно использовать pop перед вызовом P2, но вы можете просто использовать push ...", путаницы было бы меньше.

; --------------------------
CODESEG
proc cleanscreen
push cx
push bx
push ax
xor ax,ax
mov cx,4000d
mov bx,0
clean:
mov [es:bx],al
inc bx
loop clean
pop ax
pop bx
pop cx
ret
endp cleanscreen

proc playgame ;starts the game
push ax
mov ax,0b800h
mov es,ax
pop ax
call cleanscreen
push bx
push dx
mov dh, 200
mov dl, '*'
xor bx,bx
mov di,2000d
mov [es:di],dx
mov [es:di-2],dx
mov [es:di-4],dx
mov [word ptr bx], 1996d
mov [word ptr bx 1], 1998d
mov [word ptr bx 2], di
pop dx
pop bx
call random
call movement
ret
endp playgame

proc movement
mov ah,1
int 16h
jnz skip
mov ah,0
int 16h
skip:
cmp al, 'w'
je wp
cmp al, 'a'
je ap
cmp al, 'd'
je dpointer
cmp al, 's'
je spo
cmp al, 'q'
je endgame
call movement

wp:
sub di,160d
jmp update
spo:
add di, 160d
jmp update
dpointer:
add di,2d
jmp update
ap:
sub di,2d
update:
call bounderies
ret
endp movement

proc bounderies
push ax
push dx
push bx
cmp di,160d
jb endgame
cmp di, 38940
ja endgame
mov ax,di
mov bl, 160d
div bl
cmp ah,0
je endgame
inc ax
mov ax,di
div bl
cmp ah,0
je endgame
pop bx
pop dx
pop ax
call update_snake
ret
endp bounderies

proc update_snake
push bx
push si
push cx
mov cx, offset snake_length
xor bx,bx
xor ch,ch
mov si,[bx]
mov [es:si], ch
transition:
mov si,[bx 1]
mov [bx],si
loop transition
mov [bx], di
pop cx
pop si
pop bx
call delay
ret
endp update_snake

proc delay
push cx
push bx
mov cx, 0FFFFh
lopa:
mov bx, 50
lopb:
dec bx
cmp bx, 0
jnz lopb
loop lopa
ret
pop bx
pop cx
call check_if_eaten
endp delay

proc endgame
ret
endp endgame

proc check_if_eaten
cmp di, [object]
jne restfunc
call random
restfunc:
call movement
ret
endp check_if_eaten

proc random
push ax
push bx
mov ax, [Clock] ; read timer counter
mov ah, [byte cs:bx] ; read one byte from memory
xor al, ah ; xor memory and counter
and al, 00001111b ; leave result between 0-15
sal al,1
mov [byte ptr object], al
pop bx
pop ax
ret
endp random

start:
mov ax, @data
mov ds, ax
call playgame
exit:
mov ax, 4c00h
int 21h
END start

Комментарии:

1. Push в основном выводит текущее состояние (вероятно, содержимое некоторых регистров) в верхнюю часть стека. Pop восстанавливает состояния, открывая верхнюю часть стека. Если вы хотите вызвать одну процедуру P2 из другой P1, то не нужно вызывать pop перед вызовом P2, скорее вы можете просто вызвать push в начале процедуры и pop в конце процедуры. В промежутке между нажатием и щелчком может быть тело, которое также может вызывать другие процедуры.

2. Одна из проблем, которую я вижу, заключается в том, что в «задержке» у вас есть » ret » перед всплывающими окнами — это приведет к дисбалансу стека.

3. Так много вещей не так с этой программой. На то, чтобы просмотреть это, уйдет несколько часов! Пожалуйста, ответьте на этот вопрос: до того, как вы применили » push вверху и pop внизу» , программа работала или нет?

4. Один подарок: Clock equ es:6Ch Счетчик часов BIOS находится по линейному адресу 046Ch, поэтому это приравнивание будет полезно только в том случае, если регистр ES сегмента был предварительно загружен 0040h, прежде чем пытаться прочитать часы с помощью такой инструкции mov ax, [Clock] . Проверьте, так ли это в вашем коде… Предупреждение о спойлере: это не так!

5.@kiner_shah Я полностью понимаю, что вы говорите в своем комментарии, но я боюсь, что неудачный выбор слов еще больше запутает ОП. «… не нужно звонить pop перед вызовом P2, но вы можете просто позвонить push …» Если бы вы написали «… не нужно использовать pop перед вызовом P2, но вы можете просто использовать push …», путаницы было бы меньше.