使用 CGA/EGA/VGA 平面图形模式
Using the CGA/EGA/VGA planar graphics modes
我很难掌握如何在 CGA/EGA/VGA 视频图形模式中使用颜色。我特别感兴趣的视频模式是 0Dh (EGA 320x200) 和 12h (VGA 640x480)。这两种模式都有 4 个平面,因此有 16 种颜色。
我(可能不正确)的理解是我应该通过将位掩码写入端口 03C4h
来激活一组平面,然后当我写入视频内存时,数据只会写入激活的平面。大多数情况下,我使用此文档来获取我的信息,尽管我也遇到了其他几个教程和讨论:
http://www.techhelpmanual.com/89-video_memory_layouts.html
现在我正在尝试在视频存储器(屏幕左上部分)的第一个字中写入所有可能颜色的像素。我将初始位掩码的 1 加载到 AH,将 1 位加载到 BX。然后在一个循环中,我递增 AH 并移动 (SHL
) BX 中的位以在下次点击不同的像素。我 OR
BX 到 A000h:0000h
通过保持现有像素不变来添加每个像素。
我希望看到的是屏幕左上角所有可能的 16 种 EGA 颜色的像素线。我实际看到的是 7 个白色和 1 个亮黄色点,它们之间有黑色像素。我做错了什么?
另外,每个教程都说我必须在开始使用飞机之前将0005h
写入端口03CEh
。这样做的目的是什么?当我注释掉这些线条时,我仍然可以使用平面(我的意思是,在其他程序中)。以前,当我在视频内存中写入不同的字时,我成功地使用了平面(所以我不需要在一个由视频内存中的单个字表示的 16 像素块中使用不同的颜色像素);当我使用 BIOS 功能(例如 INT 10h/AH=0Ch)写入像素时,但我仍然想了解如何在没有 BIOS 的情况下使用平面图形,因为我认为 BIOS 功能很慢。
这是我的代码(缩进针对 8 宽制表符进行了优化,所以这里看起来有点不对):
; ----------------------------------------------------------------------
; PLANE - TEST PLANAR VIDEO MODE
; nasm -o plane.com plane.asm
; ----------------------------------------------------------------------
ORG 100h ; Code starts at CS:0100h
MOV AX, 0F00h ; Get current video mode
INT 10h
PUSH AX ; Save it to restore later
MOV AX, 000Dh ; Set video mode 0Dh (EGA 320x200, 16 color)
INT 10h
MOV DX, 03CEh ; Set up for plane masking
MOV AX, 0005h
OUT DX, AX
MOV AX, 0A000h ; Load video segment to ES
MOV ES, AX ; and set Destination Index
XOR DI, DI ; to write data to A000h:0000h
MOV CX, 14 ; Iterate through all plane masks
MOV AX, 0100h ; First plane mask is 01h
MOV BX, 1 ; Initial pixel to write
LOOP_PIXEL:
CALL SET_PLANES ; Set planes according to AH
PUSH BX ; Save current pixels to [DATA+CX*2]
MOV BX, CX ; for debugging purposes
SHL BX, 1
MOV DX, ES:[DI]
MOV [DATA + BX], DX
POP BX
OR ES:[DI], BX ; Add new pixel to video memory from BX
SHL BX, 1 ; Shift BX so we'll activate a different pixel next time
INC AH ; Increment plane mask
LOOP LOOP_PIXEL
XOR AX, AX ; Wait for keypress
INT 16h
POP AX ; Restore previous video mode
XOR AH, AH
INT 10h
INT 20h ; Exit program
; ----------------------------------------------------------------------
; SET_PLANES: Set video color plane mask.
;
; Inputs:
; AH - plane mask
;
; Outputs:
; None.
; ----------------------------------------------------------------------
SET_PLANES:
PUSH AX
PUSH DX
MOV DX, 03C4h
MOV AL, 02h
OUT DX, AX
POP DX
POP AX
RET
DATA:
知道为什么它没有像我预期的那样工作吗?
将字 0005h 写入端口 03CEh 和 03CFh 将 select 写入模式 0。这是一个复杂的模式,涉及 VGA 的许多功能,但对我们来说幸运的是,当视频模式为设置。
但是您的代码仍然需要执行以下操作:
- 为了填充 VGA 的内部 32 位锁存器,必须执行先读后写操作
- 使用 BitMask 寄存器将输出限制为单个或几个像素。
下一个片段显示了 16 条 1 像素宽的垂直线的彩虹:
xor di, di
mov ax, 0F02h ; First plane mask is 15
mov cx, 8008h ; First bitmask is 10000000b, Width=1
LOOP1:
mov dx, 03C4h
out dx, ax ; MapMask register
xchg ax, cx
mov dx, 03CEh
out dx, ax ; BitMask register
xchg ax, cx
xor bx, bx
.a:
mov dl, [es:di+bx]
mov byte [es:di+bx], 255
add bx, 40
cmp bx, 1600 ; Height = 40
jb .a
ror ch, 1 ; Width = 1
adc di, 0
dec ah
jns LOOP1
此代码段显示了 16 条 2 像素宽的垂直线的彩虹:
mov di, 13
mov ax, 0F02h ; First plane mask is 15
mov cx, 0C008h ; First bitmask is 11000000b, Width=2
LOOP2:
mov dx, 03C4h
out dx, ax ; MapMask register
xchg ax, cx
mov dx, 03CEh
out dx, ax ; BitMask register
xchg ax, cx
xor bx, bx
.a:
mov dl, [es:di+bx]
mov byte [es:di+bx], 255
add bx, 40
cmp bx, 800 ; Height = 20
jb .a
ror ch, 2 ; Width = 2
adc di, 0
dec ah
jns LOOP2
第三个片段显示了 16 条 4 像素宽的垂直线的彩虹:
mov di, 26
mov ax, 0F02h ; First plane mask is 15
mov cx, 0F008h ; First bitmask is 11110000b, Width=4
LOOP3:
mov dx, 03C4h
out dx, ax ; MapMask register
xchg ax, cx
mov dx, 03CEh
out dx, ax ; BitMask register
xchg ax, cx
xor bx, bx
.a:
mov dl, [es:di+bx]
mov byte [es:di+bx], 255
add bx, 40
cmp bx, 400 ; Height = 10
jb .a
ror ch, 4 ; Width = 4
adc di, 0
dec ah
jns LOOP3
已采取预防措施,因此您可以在同一个程序中同时尝试所有片段!
我很难掌握如何在 CGA/EGA/VGA 视频图形模式中使用颜色。我特别感兴趣的视频模式是 0Dh (EGA 320x200) 和 12h (VGA 640x480)。这两种模式都有 4 个平面,因此有 16 种颜色。
我(可能不正确)的理解是我应该通过将位掩码写入端口 03C4h
来激活一组平面,然后当我写入视频内存时,数据只会写入激活的平面。大多数情况下,我使用此文档来获取我的信息,尽管我也遇到了其他几个教程和讨论:
http://www.techhelpmanual.com/89-video_memory_layouts.html
现在我正在尝试在视频存储器(屏幕左上部分)的第一个字中写入所有可能颜色的像素。我将初始位掩码的 1 加载到 AH,将 1 位加载到 BX。然后在一个循环中,我递增 AH 并移动 (SHL
) BX 中的位以在下次点击不同的像素。我 OR
BX 到 A000h:0000h
通过保持现有像素不变来添加每个像素。
我希望看到的是屏幕左上角所有可能的 16 种 EGA 颜色的像素线。我实际看到的是 7 个白色和 1 个亮黄色点,它们之间有黑色像素。我做错了什么?
另外,每个教程都说我必须在开始使用飞机之前将0005h
写入端口03CEh
。这样做的目的是什么?当我注释掉这些线条时,我仍然可以使用平面(我的意思是,在其他程序中)。以前,当我在视频内存中写入不同的字时,我成功地使用了平面(所以我不需要在一个由视频内存中的单个字表示的 16 像素块中使用不同的颜色像素);当我使用 BIOS 功能(例如 INT 10h/AH=0Ch)写入像素时,但我仍然想了解如何在没有 BIOS 的情况下使用平面图形,因为我认为 BIOS 功能很慢。
这是我的代码(缩进针对 8 宽制表符进行了优化,所以这里看起来有点不对):
; ----------------------------------------------------------------------
; PLANE - TEST PLANAR VIDEO MODE
; nasm -o plane.com plane.asm
; ----------------------------------------------------------------------
ORG 100h ; Code starts at CS:0100h
MOV AX, 0F00h ; Get current video mode
INT 10h
PUSH AX ; Save it to restore later
MOV AX, 000Dh ; Set video mode 0Dh (EGA 320x200, 16 color)
INT 10h
MOV DX, 03CEh ; Set up for plane masking
MOV AX, 0005h
OUT DX, AX
MOV AX, 0A000h ; Load video segment to ES
MOV ES, AX ; and set Destination Index
XOR DI, DI ; to write data to A000h:0000h
MOV CX, 14 ; Iterate through all plane masks
MOV AX, 0100h ; First plane mask is 01h
MOV BX, 1 ; Initial pixel to write
LOOP_PIXEL:
CALL SET_PLANES ; Set planes according to AH
PUSH BX ; Save current pixels to [DATA+CX*2]
MOV BX, CX ; for debugging purposes
SHL BX, 1
MOV DX, ES:[DI]
MOV [DATA + BX], DX
POP BX
OR ES:[DI], BX ; Add new pixel to video memory from BX
SHL BX, 1 ; Shift BX so we'll activate a different pixel next time
INC AH ; Increment plane mask
LOOP LOOP_PIXEL
XOR AX, AX ; Wait for keypress
INT 16h
POP AX ; Restore previous video mode
XOR AH, AH
INT 10h
INT 20h ; Exit program
; ----------------------------------------------------------------------
; SET_PLANES: Set video color plane mask.
;
; Inputs:
; AH - plane mask
;
; Outputs:
; None.
; ----------------------------------------------------------------------
SET_PLANES:
PUSH AX
PUSH DX
MOV DX, 03C4h
MOV AL, 02h
OUT DX, AX
POP DX
POP AX
RET
DATA:
知道为什么它没有像我预期的那样工作吗?
将字 0005h 写入端口 03CEh 和 03CFh 将 select 写入模式 0。这是一个复杂的模式,涉及 VGA 的许多功能,但对我们来说幸运的是,当视频模式为设置。
但是您的代码仍然需要执行以下操作:
- 为了填充 VGA 的内部 32 位锁存器,必须执行先读后写操作
- 使用 BitMask 寄存器将输出限制为单个或几个像素。
下一个片段显示了 16 条 1 像素宽的垂直线的彩虹:
xor di, di
mov ax, 0F02h ; First plane mask is 15
mov cx, 8008h ; First bitmask is 10000000b, Width=1
LOOP1:
mov dx, 03C4h
out dx, ax ; MapMask register
xchg ax, cx
mov dx, 03CEh
out dx, ax ; BitMask register
xchg ax, cx
xor bx, bx
.a:
mov dl, [es:di+bx]
mov byte [es:di+bx], 255
add bx, 40
cmp bx, 1600 ; Height = 40
jb .a
ror ch, 1 ; Width = 1
adc di, 0
dec ah
jns LOOP1
此代码段显示了 16 条 2 像素宽的垂直线的彩虹:
mov di, 13
mov ax, 0F02h ; First plane mask is 15
mov cx, 0C008h ; First bitmask is 11000000b, Width=2
LOOP2:
mov dx, 03C4h
out dx, ax ; MapMask register
xchg ax, cx
mov dx, 03CEh
out dx, ax ; BitMask register
xchg ax, cx
xor bx, bx
.a:
mov dl, [es:di+bx]
mov byte [es:di+bx], 255
add bx, 40
cmp bx, 800 ; Height = 20
jb .a
ror ch, 2 ; Width = 2
adc di, 0
dec ah
jns LOOP2
第三个片段显示了 16 条 4 像素宽的垂直线的彩虹:
mov di, 26
mov ax, 0F02h ; First plane mask is 15
mov cx, 0F008h ; First bitmask is 11110000b, Width=4
LOOP3:
mov dx, 03C4h
out dx, ax ; MapMask register
xchg ax, cx
mov dx, 03CEh
out dx, ax ; BitMask register
xchg ax, cx
xor bx, bx
.a:
mov dl, [es:di+bx]
mov byte [es:di+bx], 255
add bx, 40
cmp bx, 400 ; Height = 10
jb .a
ror ch, 4 ; Width = 4
adc di, 0
dec ah
jns LOOP3
已采取预防措施,因此您可以在同一个程序中同时尝试所有片段!