组装在模式 x 中读取平面是否需要与写入不同的输出到 VGA 端口?

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

1我在 DosBox 0.74 上用 TASM 3.0 写,我想用模式 x(调整 13h,非链接模式 13)写,我遇到了一个问题,你如何在图像中看到,每一行都被打印出来,但是在每行,每组四个像素只打印第一个像素的颜色,这是在VRAM中的不同空间打印图像进行双缓冲后,因此所有四个平面都有第一个平面的数据。

这是图像的打印方式(这是没有双缓冲区的直接打印,是的,计时器有问题,但没关系)

在此处输入图片说明

这是使用双缓冲打印图像的方式

在此处输入图片说明

我确实认为问题在于模式x时VGA端口中的数据与读写不同,这里是选择VGA平面的代码

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)

如果输出不是问题,这里是内存传输的代码:

    proc DoubleBuffer
    mov ax, 0A000h
    mov es, ax
    mov [VGAPlane], 0
    call VGAPlaneSelect
    cli
    mov cx, 4
    DoubleBuffer_loop:
        xor di, di
        xor si, si
        push cx
        mov cx, 16000
        DoubleBuffer_loop_plane: 
            push di
            push si
            shr di, 2
            shr si, 2
            add si, NON_VISABLE_PLANE_OFFSET
            mov al, [es:si]
            stosb
            pop si
            pop di
            add di, 4
            add si, 4
        loop DoubleBuffer_loop_plane
        inc [VGAPlane]
        call VGAPlaneSelect
        pop cx
    loop DoubleBuffer_loop
    sti
    ret
endp pageFlipping
Run Code Online (Sandbox Code Playgroud)

Sep*_*and 3

在 VGA 的图形控制器中,有一个单独的寄存器来指定要读取的平面。

您可以通过在地址端口 03CEh 中写入 4,然后在数据端口 03CFh 中写入平面编号 (0-3) 来选择它。

您使用的 03C4h:02h 寄存器称为 ColorPlane Write Enable。答案已经在它的名字里了!它允许同时写入一个或多个平面。如需读取,请使用 03CEh:04h ReadPlaneSelect。


proc DoubleBuffer
...
endp pageFlipping
Run Code Online (Sandbox Code Playgroud)

是哪一个?

PageFlipping 不需要像此过程那样复制大块内存。
DoubleBuffering 的想法是使用“普通”RAM 构建图片并将其全部或部分复制到视频内存。您的程序使用视频内存来保存双缓冲区,因此读取速度会非常慢!

为什么DoubleBuffer_loop如此复杂?

您根本不需要这种转移和保存!

    xor di, di
    mov si, NON_VISABLE_PLANE_OFFSET
    mov cx, 16000
DoubleBuffer_loop_plane: 
    mov al, [es:si]
    stosb
    inc si
    dec cx
    jnz DoubleBuffer_loop_plane
Run Code Online (Sandbox Code Playgroud)

这可以进一步简化为:

    xor di, di
    mov si, NON_VISABLE_PLANE_OFFSET
    mov cx, 16000
    cld
    rep movs byte [di], [es:si]
Run Code Online (Sandbox Code Playgroud)

的语法rep movs取决于您使用的汇编器。在 NASM 中,您必须在REP MOVSB指令之前添加段覆盖,因此ES REP MOVSB