组装 x86-16 中的模式 X,为什么平面 1 不打印,所有其他平面的顺序都不正确?

Eri*_*fat 6 graphics assembly dos vga x86-16

我在 DosBox 0.74 上用 TASM 3.0 编写,我正在尝试在模式 x(调整 13h,未链接模式 13)中编写,但在这里您可以在图像中看到,它不太正确。似乎平面 1(第二个平面)根本没有打印,所有其他平面的顺序都不正确。我知道这里的代码效率低下,但我想让它工作然后清理它。

输出

proc showBMP
    push cx
    mov ax, 0A000h
    mov es, ax
    mov cx, [BMPHeight]
    mov ax, [BMPWidth]
    xor dx, dx
    mov si, 4
    div si
    mov bp, dx
    mov dx, [BMPX]
    showBMP_nextLine:
        call VGAPlaneStartBMP
        push cx
        push dx
        mov di, cx
        add di, [BMPY]
        mov cx, di
        shl cx, 6
        shl di, 8
        add di, cx
        add di, dx
        mov ah, 3fh
        mov cx, [BMPWidth]
        add cx, bp
        mov dx, offset BMPMaxLine
        int 21h
        cld
        mov cx, [BMPWidth]
        mov si, offset BMPMaxLine
        showBMP_nextLine_movsbLoop:
            push cx
            push di
            shr di, 2
            mov cl, [ds:si]
            mov [es:di], cl
            inc [VGAPlane]
            inc si
            pop di
            inc di
            pop cx
            call VGAPlaneSelect
        loop showBMP_nextLine_movsbLoop
        pop dx
        pop cx
    loop showBMP_nextLine
    pop cx
    ret
endp showBMP
Run Code Online (Sandbox Code Playgroud)

在这里您可以看到打印位图文件的过程,该过程在链 4 模式 13 上完美运行。

  • BMPHeight - 顾名思义就是图片的高度
  • BMPWidth - 相同
  • BMPX - 图片在屏幕上的起始位置(x 坐标)
  • BMPY - 相同但 Y 坐标
  • BMPMaxLine - 320 的数组用作缓冲区
  • VGAPlane - 0/1/2/3 平面之一
  proc VGAPlaneStartBMP
       push ax
       push bx
       mov ax, [BMPX]
       mov bx, offset PlaneByX
       add bx, ax
       mov al, [bx]
       mov [VGAPlane], al
       pop bx
       pop ax
       call VGAPlaneSelect
       ret
   endp VGAPlaneStartBMP
Run Code Online (Sandbox Code Playgroud)

这个过程,对于每一行打印,通过一行的起始 x 选择平面:

  • PlaneByX - MAX_WIDTH / NUMBER_OF_PLANES dup (PLANES),重置

  • MAX_WIDTH 为 320,NUMBER_OF_PLANES 为 4,PLANES 为 0、1、2、3,

proc VGAPlaneSelect
        push ax
        push dx
        mov al, 02h
        mov dx, 03C4h
        out dx, al
        VGAPlaneSelect_start:
        cmp [VGAPlane], 0
        jne VGAPlaneSelect_0
            mov al, 0h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_0:
        cmp [VGAPlane], 1
        jne VGAPlaneSelect_1
            mov al, 1h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_1:
        cmp [VGAPlane], 2
        jne VGAPlaneSelect_2
            mov al, 4h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_2:
        cmp [VGAPlane], 3
        jne VGAPlaneSelect_3
            mov al, 8h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_3:
            mov [VGAPlane], 0
            jmp VGAPlaneSelect_start
        VGAPlaneSelect_end:
        inc dx
        out dx, al
        pop dx
        pop ax
        ret
    endp VGAPlaneSelect
Run Code Online (Sandbox Code Playgroud)

最后这个代码是在选择飞机时。

Eri*_*fat 2

感谢 Fuz 找到答案,感谢 Jonathon Reinhart 让我的问题更加清晰。在VGAPlaneSelect过程中,al值是0x3c5 VGA地址的输出,应该是2^(你想要选择的平面),对于平面0 2^0它应该是1,我写了0

所以:

        cmp [VGAPlane], 0
        jne VGAPlaneSelect_0
            mov al, 1h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_0:
Run Code Online (Sandbox Code Playgroud)

执行此VGAPlaneSelect过程的更好方法是:

    proc VGAPlaneSelect
        push ax
        push dx
        push cx
        mov al, 02h
        mov dx, 03C4h
        out dx, al
        VGAPlaneSelect_start:
        mov ax, 1
        mov cl, [VGAPlane]
        shl ax, cl
        cmp [VGAPlane], 4
        jne VGAPlaneSelect_end
            mov [VGAPlane], 0
            jmp VGAPlaneSelect_start
        VGAPlaneSelect_end:
        mov dx, 03C5h
        out dx, al
        pop cx
        pop dx
        pop ax
        ret
    endp VGAPlaneSelect
Run Code Online (Sandbox Code Playgroud)

  • 您使用班次更新的代码仍然严重过于复杂!看来你只需要将班次计数限制为 0..3 即可。您可以在移位之前执行此操作,并且可以使用“cmp cl,4”而不是再次检查内存并重做移位。或者你可以只是 `mov cl, [VGAPlane]` ;`移动斧头,1`;`and cl, 3`(屏蔽高位);`shl ax, cl` 如果您不需要实际重置内存中的值。 (2认同)