程序集 x86-16 中的模式 X,为什么平面 1 未打印且所有其他平面的顺序不正确?
Mode X in Assembly x86-16, Why is plane 1 not printing and all the other planes are not in the correct order?
我在 DosBox 0.74 上用 TASM 3.0 写,我正在尝试用 Mode x (Tweaked 13h, unchained mode 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
在这里您可以看到打印位图文件的过程,它在 chain-4 模式 13 上完美运行。
- BMPHeight - 顾名思义就是图片的高度
- BMP 宽度 - 相同
- 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
这个程序,对于每行打印,通过一行的起始x来选择平面:
PlaneByX - MAX_WIDTH / NUMBER_OF_PLANES dup (PLANES), RESET
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
最后这段代码是选择飞机时的代码。
感谢 Fuz 找到答案,感谢 Jonathon Reinhart 让我的问题更清楚。
在 VGAPlaneSelect 程序中,作为 0x3c5 VGA 地址输出的 al 值应为 2^(您要选择的平面),对于平面 0 2^0,它应为 1,我写了 0
所以:
cmp [VGAPlane], 0
jne VGAPlaneSelect_0
mov al, 1h
jmp VGAPlaneSelect_end
VGAPlaneSelect_0:
执行 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
我在 DosBox 0.74 上用 TASM 3.0 写,我正在尝试用 Mode x (Tweaked 13h, unchained mode 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
在这里您可以看到打印位图文件的过程,它在 chain-4 模式 13 上完美运行。
- BMPHeight - 顾名思义就是图片的高度
- BMP 宽度 - 相同
- 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
这个程序,对于每行打印,通过一行的起始x来选择平面:
PlaneByX - MAX_WIDTH / NUMBER_OF_PLANES dup (PLANES), RESET
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
最后这段代码是选择飞机时的代码。
感谢 Fuz 找到答案,感谢 Jonathon Reinhart 让我的问题更清楚。 在 VGAPlaneSelect 程序中,作为 0x3c5 VGA 地址输出的 al 值应为 2^(您要选择的平面),对于平面 0 2^0,它应为 1,我写了 0
所以:
cmp [VGAPlane], 0
jne VGAPlaneSelect_0
mov al, 1h
jmp VGAPlaneSelect_end
VGAPlaneSelect_0:
执行 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