装配从一个阵列复制到另一个阵列

时间:2018-05-19 13:41:10

标签: assembly x86 masm isa

抱歉标题,我无法想象用英语表达这种方式。 因此,我正在为一个课程编写一个小小的游戏,并且,在两个for循环中,我复制来自"炸弹的像素数据"像素矢量,到"区域"像素矢量,稍后将被绘制到屏幕上。在C中,它应该如下所示:

int x, y;
for(int i=0;i<32;i++)
    for(int j=0;j<32;j++)
        area[x+i][y+j]=bomb[i][j];

使用masm汇编程序和notepad ++编写代码,我得到了

mov ecx, 0 ; my i
outerloop:
    cmp ecx, 32
    je done
    mov esi, 0 ; my j
innerloop:
    mov ebx, sprite_width ; sprite_width=32
    mov eax, ecx
    mul ebx
    add eax, esi
    shl eax, 2
    mov edi, bomb
    add edi, eax
    mov pixel, edi  ; pixel = bomb[i][j]
    mov ebx, area_width
    mov eax, y
    add eax, ecx
    mul ebx
    add eax, x
    add eax, esi
    shl eax, 2
    mov edi, area
    add edi, eax
    mov eax, [pixel]
    mov dword ptr [edi], eax   ; should be area[x+i][y+j] = pixel
    cmp esi, 32
    je innerloopdone
    inc esi
    jmp innerloop
innerloopdone:
    inc ecx
    jmp outerloop
done:

在此之后,屏幕中的32x32区域应该看起来像炸弹,因为炸弹矢量是如何写的,但是我只看到一些绿色和一些蓝色。蓝色根本不在炸弹矢量中。循环/逻辑中是否有错误?

1 个答案:

答案 0 :(得分:3)

由于你没有发布这些符号的定义,我只是猜测它们是如何定义的,我希望会有类似的东西:

area            dd  640*480 dup (0)         ; 640x480x32bpp "screen area"
area_width      dd  640
sprite_width    dd  32
sprite_height   dd  32
bomb            dd  32*32 dup (255)         ; 32x32 red pixels as "bomb" gfx placeholder

然后,这应该足以以比您的提议更有效的方式绘制不透明的图形:

    ; initialize registers before drawing lines
    ; make edi = address area[y][x]
    lea     edi,[area]
    mov     ebx,[area_width]
    mov     eax,[y]
    mul     ebx
    add     eax,[x]     ; eax = y*area_width + x
    shl     eax,2
    add     edi,eax     ; edi = area + (y*area_width + x)*4
    ; make ebx = (area_width - sprite_width)*4
    sub     ebx,[sprite_width]
    shl     ebx,2
    ; make esi = address bomb[0][0]
    lea     esi,[bomb]
    ; make edx = number of lines
    mov     edx,[sprite_height]   ; 32
line_loop:
    ; draw single line
    mov     ecx,[sprite_width]
    rep movsd
    ; move to the next line (esi already updated, edi must advance)
    add     edi,ebx
    ; loop until all lines are drawn
    dec     edx
    jnz     line_loop

我没有调试它,所以可能有问题,但我没有MASM可以尝试。

关于您的原始代码,有一个反复出现的主题,您可以在其中编写以下内容:

    mov edi, bomb

VS

    mov eax, [pixel]

不幸的是,在MASM中这些是相同的,当您使用[]名称时不需要symbol内存访问,即mov edi,bomb正在从内存加载值,而不是获取炸弹的地址。要获取地址,请使用MASM中的mov edi,OFFSET bomblea edi,[bomb]

所以你混淆了这些,有时它看起来你确实想得到内存地址,有时候是值,有时你将地址存储到内存而不是值等等......

此外,我强烈建议您开始在符号周围使用[],即使MASM不需要它们,因此代码访问内存的行在视觉上更容易被发现,并且样式与间接寻址相同寄存器(即与mov eax,[ebx]相同的样式,即使MASM需要方括号)。检查我的示例,我如何在每次内存访问时始终使用[]lea除外,其中CPU将访问内存,只计算地址,但这是由于lea指令本身,它的参数仍然是memory-access-type)。

但最重要的是为您的平台找到一些有效的调试器,并学会使用它,因为在没有调试器的情况下进行汇编编程就像尝试组装机器人蒙上眼睛一样。你可以做到,但这要困难得多,需要很多技巧和经验。这是您目前的主要问题,代码的代码风格和效率就像问题的10%,无法调试您的代码是90%。