使用CGA/EGA/VGA平面图形模式

4
我很难理解如何在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中的位以下一次击中不同的像素。我通过离开已存在的像素不变来将BX ORA000h:0000h 中添加每个像素。

我期望看到的是屏幕左上角所有可能的16种EGA颜色构成的一行像素。然而我实际看到的是7个白点和1个亮黄色点,并且它们之间有黑色像素。我做错了什么?

此外,每个教程都说在使用平面之前必须向端口03CEh写入0005h。这样做的目的是什么?当我将这些代码注释掉后,我仍然可以在其他程序中使用平面(我的意思是)在以前的编程中,当我在视频内存中写入不同单词时(所以我不需要一个由视频内存中的单个字表示的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:

任何想法为什么它不按我预期的工作?
1个回答

3
将单词0005h写入端口03CEh和03CFh将选择写模式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

为了让您能够尝试在同一个程序中使用所有片段,我们已经采取了相应的预防措施!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接