簡體   English   中英

為什么在 VGA 模式下寫入圖形內存的寫入模式不會改變?

[英]Why wont the write mode change for writing to graphics memory in VGA mode?

我正在嘗試使用 NASM 在 DOSBOX 中的 VGA 圖形中繪制屏幕。 我的代碼能夠完美地寫入黑屏,但是如果我編輯一個已經是某種顏色的像素,輸出顏色最終會是以前的顏色與我的新顏色相或。 例如,如果我填充紅色屏幕,然后再次將其填充為藍色,則最終屏幕將不是藍色,而是洋紅色。

這是我的代碼,它應該先填充屏幕藍色然后再填充綠色,而是填充屏幕藍色然后將藍色內存與綠色進行 OR 運算,從而產生青色填充屏幕。 通過降低 CPU 速度,我能夠在 DOSBOX 中看到這種情況。

org 100h
section .text
start:
    mov ax, 4F02h
    mov bx, 102h
    int 10h       ; enter 800x600 16 color VGA mode
    push 0x01     ; blue
    call fill_screen
    push 0x2      ; green
    call fill_screen
    jmp $

fill_screen:
    ; multiply screen width by height then divide by 8 to get number of times to repeat write operation, push to stack
    mov ax, [screen_width]
    mov dx, [screen_height]
    mul dx
    mov cx, 8
    div cx
    push ax

    ; point es to video memory
    mov ax, 0A000h
    mov es, ax

    pop cx  ; times to repeat write operation
    pop dx  ; return address
    pop ax  ; color 
    push dx ; put return address back on stack
    
    mov dx, 03c4h ; register selection port
    shl ax, 8     ; color is one byte, it was in al but we need it in ah so shift left one byte
    mov al, 02h   ; map mask
    out dx, ax    ; write all the bitplanes
    xor di, di    ; video memory pointer to start
    mov ax, 0ffh  ; write to every pixel
    rep stosb
    ret

section .data
    screen_width dw 320h
    screen_height dw 258h

在第 5 節,它說您可以通過寫入端口 03CFh 將寫入模式更改為替換、或、異或或和。 它們包括切換到 XOR 模式的示例代碼:

mov ax,1803h
mov dx,03CEh
out dx,ax

當我在第 6 行(int 10h)之后添加它時,什么也沒有發生,代碼的輸出仍然是青色。 由於藍色 OR 綠色與藍色 XOR 綠色相同,我將綠色輸入更改為洋紅色(使第 9 行push 0x5 )。 輸出現在為洋紅色,這意味着內存仍處於 OR 模式而不是 XOR 模式。

這是最終的測試代碼:

org 100h
section .text
start:
    mov ax, 4F02h
    mov bx, 102h
    int 10h       ; enter 800x600 16 color VGA mode

    ; switch to XOR write mode (?)
    mov ax, 1803h
    mov dx, 03CEh
    out dx, ax

    push 0x01 ; blue
    call fill_screen
    push 0x5 ; magenta
    call fill_screen
    jmp $

fill_screen:
    ; multiply screen width by height then divide by 8 to get number of times to repeat write operation, push to stack
    mov ax, [screen_width]
    mov dx, [screen_height]
    mul dx
    mov cx, 8
    div cx
    push ax

    ; point es to video memory
    mov ax, 0A000h
    mov es, ax

    pop cx  ; times to repeat write operation
    pop dx  ; return address
    pop ax  ; color 
    push dx ; put return address back on stack

    mov dx, 03c4h ; register selection port
    shl ax, 8     ; color is one byte, it was in al but we need it in ah so shift left one byte
    mov al, 02h   ; map mask
    out dx, ax    ; write all the bitplanes
    xor di, di    ; video memory pointer to start
    mov ax, 0ffh  ; write to every pixel
    rep stosb
    ret

section .data
    screen_width dw 320h
    screen_height dw 258h

我該如何解決這個問題,以便我進入不同的寫入模式? 有沒有更好的方法來寫入視頻內存,放棄我應該使用的寫入模式? 我將如何進入替換模式?

關於 VGA 硬件的一些參考: https ://wiki.osdev.org/VGA_Hardware , https://web.stanford.edu/class/cs140/projects/pintos/specs/freevga/vga/vgamem.htm

首先,XOR 模式(和其他模式)不與視頻內存中已經存在的數據進行 XOR。 它們與從視頻內存讀取時加載的鎖存寄存器進行異或。 鎖存寄存器保持它們的值,直到您從視頻內存中讀取另一個值。 如果您不從視頻內存中讀取,則鎖存寄存器具有未定義的值。

要保持正常模式(NOP 模式),只需將模式設置為 0:

mov ax,0003h
mov dx,03CEh
out dx,ax

此外,在寫入 03c4h/reg 2 時,您設置了一個掩碼,該掩碼將應用於對視頻內存的所有寫入,過濾您寫入的每一位。 將掩碼設置為 0Fh 將允許按預期寫入所有位。 如果您不使用掩碼值 0Fh(在您的情況下,您可以用您的顏色填充它),那么掩碼的 0 位將從鎖存寄存器中獲取,您沒有設置,因為您沒有不讀。

要寫入不帶遮罩的顏色,請將遮罩設置為 0Fh,並寫入您的實際顏色而不是 FFh:

mov dx,03C4h
mov ax,0F02h
out dx,ax
mov es:[di], <color> ; example write

如果您希望對每個像素使用 XOR 和掩碼操作,則需要在每次寫入之前通過執行虛擬讀取正確填充鎖存器:

mov bl, es:[di] ; ignore bl if not needed
mov es:[di], <color> ; example write with VGA operations

請注意,使用bl並自己執行 xor/mask 的替代方法並不復雜。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM