繁体   English   中英

如何在 x86 中保留数组或字符串

[英]How to preserve an array or string in x86

我正在使用 tasm asm/dosbox 在 x86 中编写游戏“15 益智游戏”。 我想“保存”或“保留”在我的数据段中声明的名为“a”的数组,以便在使用 upArrow、downArrow 等交换字节后...然后按“n”新游戏,我可以将我的数组“a”设置回原来的 state,因为它在我的数据段中声明。 这是我的代码:

.MODEL TINY
.386

.DATA
PROMPT DB "Enter q to quit, arrow keys to move, n to restart (new game) HAPPY HOLIDAYS!! :)$"

;this is board preset A
a       DB 201,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,187,
    DB 186,255,48,50,255,186,255,48,49,255,186,255,48,51,255,186,255,48,52,255,186,255,48,53,255,186,255,48,54,255,186,
    DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185,
    DB 186,255,48,55,255,186,255,48,56,255,186,255,48,57,255,186,255,49,48,255,186,255,49,49,255,186,255,49,50,255,186,
    DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185, 
    DB 186,255,49,51,255,186,255,49,52,255,186,255,49,53,255,186,255,49,54,255,186,255,49,55,255,186,255,255,255,255,186,
    DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185, 
    DB 186,255,49,56,255,186,255,49,57,255,186,255,50,48,255,186,255,50,49,255,186,255,50,50,255,186,255,50,51,255,186,
    DB 200,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,188,"$"


col DB 0
row DB 0
board DB 0

.CODE
org 100h
MAIN PROC

;initialize display step 0
MOV AH, 00h
MOV AL, 03h
INT 10h

MOV AX, 0B800h
MOV ES, AX
XOR di,di


;initialize configuration and dislay prompt step 1
newGame:
call initConfig

;display board step 2


;wait for key step 3
game:
;print board
call printBoard1

;get cursor x y
call SetCursor

MOV AH, 0
INT 16H

MOV BL, AL

;up arrow
CMP AH, 48h
jz upArrow

;down arrow
CMP AH, 50h
jz downArrow

;right arrow
CMP AH, 4dh
jz rightArrow

;left arrow
CMP AH, 4bh
jz leftArrow

;lowercase q
CMP AL, 71h
jz EXIT

;uppercase q
CMP AL, 51h
jz EXIT

;lowercase n
CMP AL, 6eh
jz newGame

;uppercase n
CMP AL, 4eh
jz newGame

jmp game

MAIN ENDP

EXIT:
MOV AH, 4CH                  ; return control to DOS
INT 21H

SetCursor:
mov dl, col
mov dh, row
mov bh, 0
mov ah, 02h
int 10h
ret

getStrlen:
lodsb
cmp al, 24h
je strlen_end
inc bx
jmp getStrlen
strlen_end:
ret

loadAndDisplayStr:
lodsb
stosw
dec cx
jne loadAndDisplayStr
ret

printBoard1:
MOV board, 1
xor dx,dx
xor ax,ax
mov cx, 9
myloop1:
push cx
lea si, a
add si, dx
mov cx, 31
mov di, ax
push ax
mov ah, 4
call loadAndDisplayStr
pop ax
add ax, 160
add dx, 32
pop cx
dec cx
jnz myloop1
ret

upArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
sub row, 2
mul row
add al, col
mov di, ax
mov ax, 32
add row, 2
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
sub row, 2
jmp game

downArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
add row, 2
mul row
add al, col
mov di, ax
mov ax, 32
sub row, 2
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
add row, 2
jmp game

leftArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
sub col, 5
mul row
add al, col
mov di, ax
mov ax, 32
add col, 5
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
sub col, 5
jmp game

rightArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
add col, 5
mul row
add al, col
mov di, ax
mov ax, 32
sub col, 5
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
add col, 5
jmp game

initConfig:
;put the cursor at 00
mov col, 27
mov row, 5

;gets strlen of prompt and stores it in BX
lea si, PROMPT
xor bx, bx
call getStrlen

;display prompt
lea si, PROMPT
mov cx, bx
mov ah, 2
mov di, 5a0h
call loadAndDisplayStr
ret

END MAIN

我认为有两种方法可以做到这一点。 一种方法是创建一个空数组,每次用户移动(上/下/左/右)时,我都可以将其推送到堆栈中,然后当用户为新游戏点击“n”时,我只是弹出该堆栈并反转所有动作。

另一种选择是创建2个相同的板(数组/字符串)'a'和'b',然后用户将操纵板'a'直到他们决定为新游戏点击'n',然后我会一些如何设置'a' = 'b'

没有什么神奇的方法,你只需要像在 C 中一样复制数组。 我建议拥有一份您保持干净/未触及的数据的主副本,永远不要写入它。

为工作游戏 state 分配未初始化的空间,例如在堆栈上或 BSS 1中。

在每场比赛开始时(包括第一场比赛),将预设的整个数组复制到当前比赛的暂存空间。 (例如,在设置 CX、SI 和 DI 之后使用rep movsbrep movsw和 DS 段 regs 已经是相等的段,因为。model tiny。即实现一个 memcpy,但你喜欢。)

所以你不需要写两次初始化数据或类似的东西,文件中只需要一个副本。

不,你不需要任何交换,只是一个块副本。 通过在末尾放置 label 或将datasize = $ - a放在a的末尾之后,让汇编器计算整个事物的大小,以获取以字节为单位的大小。


脚注 1 :有关如何在.data? 段,以便您可以使用正常的标签/符号语法。 gamestate datasize dup(?)一样,其中datasize是一个=equ常量,您可以让汇编器从预设的大小更早地进行计算。

我认为.data? 只是 DOS 加载您的.com文件的末尾之后的空间,您可以使用从那里到程序加载器放置堆栈的 64k 段末尾附近的空间。 (与现代操作系统下的 .bss 不同,一开始并没有归零。这很好,你想在阅读/修改之前写下你使用的空间。)


@DavidWohlferd 还建议您可以使用 DOS 文件打开/读取系统调用从磁盘重新读取部分可执行文件。 这可能是保存游戏机制的开始。 在最简单的形式中,如果您的程序的前n个字节都是只读的(代码和常量数据),除了这个游戏状态数组,您可以将原始.com文件的前n个字节读取到ds:100h (或cs或es,在微型memory模型中都是一样的)。 用自己覆盖指令(比如对数据的jmp rel16 )很好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM