【问题标题】:x86 Video mode Clear Screenx86 视频模式 清屏
【发布时间】:2023-12-22 05:27:01
【问题描述】:

您好,我正在尝试使用此代码在 DOS 视频模式下清除屏幕。

但是当我运行它时,点仍然存在!

    org 100h

    mov     ah, 0       ; set display mode function.
    mov     al, 13h     ; mode 13h = 640x480 pixels, 256 colors.
    int     10h         ; set it!

    mov     cx, 10      ; column
    mov     dx, 10      ; row
    mov     al, 15      ; white
    mov     ah, 0ch     ; put pixel
    int     10h         ; draw pixel

    ; -------  clear the screen ----------     
    ; -------  doesn't work! dot is still there

    mov ax,0B800h
    mov es,ax
    xor di,di
    xor ax,ax
    mov cx,2000d
    cld
    rep stosw

    ; -------------------------------------

    ;wait for keypress
    mov ah,00
    int 16h

    mov ax, 4c00h ; exit to operating system.
    int 21h

    ;======================================================

我尝试使用 INT 10 重置视频模式,但这让我闪烁,这在我的循环中是不需要的

【问题讨论】:

  • 模式 13h 是 320x200 而不是 640x480,缓冲区位于段 0xa000,而不是 0xb800,缓冲区大小是 32000 字而不是 2000。

标签: assembly x86 nasm dos bios


【解决方案1】:

您的代码存在一些问题。

首先,BIOS 模式 13h 不是 8 位/像素的 640x480,而是 8 位/像素的 320x200。

B800h 是 BIOS 文本模式的地址。 BIOS 图形模式使用 A000h。

应该是这样的:

mov ax,0A000h
mov es,ax

8 位的 320x200 消耗 320*200 = 64 000 字节的视频内存。所以cx 的值不正确。应该是:

mov cx,32000d
cld
rep stosw

【讨论】:

  • s/16000/32000/ 否则 +1
  • @user786653 已修复。我在想,在 32 位 DOS 代码中我会这样做 xor eax,eax; mov ecx,16000d; rep stosd 然后把自己弄糊涂了......
  • 这解释了很多,现在很顺利 :D 非常感谢 :)
  • 请注意,您可以执行mov cx,320*200/2 之类的操作,以使其更易于阅读(更容易看到“幻数”的来源)并且不易出错。汇编器将为您计算常数。
【解决方案2】:

对于文本模式,您可以使用这个简单的过程

clrscr proc
    mov ax,0003h
    int 10h 
    ret
endp

并在你的程序中调用它

call clrscr

【讨论】:

  • 问题是他没有使用文本模式,这会将视频模式更改为文本模式。他还尝试将视频模式重置为他实际使用的模式,但这会导致不必要的闪烁。
【解决方案3】:

下一个代码适用于 msdos 5.0。它适用于 vga 模式(640x480 像素和 16 种颜色的调色板)。

BORRARPANTALLAVGA:
;Erases the screen in graphic mode
;Input:
;CH: Background color.
    PUSH    AX
    PUSH    CX
    PUSH    DX
    PUSH    DI
    PUSH    ES
    MOV     DX,     3C4H
    MOV     AX,     0F02H
    OUT     DX,     AX
    MOV     DX,     3CEH
    MOV     AH,     CH
    XOR     AL,     AL
    OUT     DX,     AX
    MOV     AX,     0F01H
    OUT     DX,     AX
    MOV     CX,     19200
    XOR     DI,     DI
    MOV     AX,     0A000H
    MOV     ES,     AX
    CLD
    REP     STOSW
    MOV     DX,     3CEH
    MOV     AX,     1
    OUT     DX,     AX
    POP     ES
    POP     DI
    POP     DX
    POP     CX
    POP     AX
    RET

我希望这会有所帮助。

请原谅我可能的错误。

代码已重新编辑,以包含 Michael Petch 的更正。谢谢迈克尔。

如果你需要阅读一些文档,可以在这里阅读:

Online ebook about vga programming

【讨论】:

  • 你应该解释一下这段代码,因为它可能对某些人理解它为什么起作用没有用处。不过,这段代码有一个错误。您的代码假定当前启用了 4 位平面,这可能是也可能不是。你真的应该确保它们都启用了MOV DX, 3C4HMOV AX, 0F02HOUT DX, AX
  • 你也做了一件不寻常的事情来设置CX。您将 AX 中的值乘以 40。如果您知道屏幕尺寸为 640*480,那么清除它所需的字数将为 640*(480/8)/2 。而不是 MOV BX, 40 MUL BX MOV CX, AX 您可以将其替换为 MOV CX, 640*(480/8)/2 。您的方法恰好使需要清除的屏幕内存地址数量增加了一倍。