首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

組合語言技巧:圖形模式下螢幕內容的高效保存與恢復(利用 VESA/INT 10h 不清除顯存切換模式)

     編輯:組合語言

前言

在 DOS 時代編寫內存駐留程式(TSR)或需要彈出視窗的工具時,常面臨一個難題:如何保存當前圖形模式下的螢幕內容?高解析度、真彩色模式下顯存高達數 MB(如 1024×768×32bpp ≈ 3MB),直接複製到常規記憶體不現實,需用磁碟交換或 XMS,極大增加複雜度。本文介紹一種巧妙技巧:利用 INT 10h AH=00h 位元 7 置位(不清除顯存切換模式) 結合 VESA 功能,將任意圖形模式下的可見畫面「壓縮」保存到約 10KB 緩衝區,後續恢復同樣高效。

核心原理

  1. 檢測顯示卡類型:INT 10h AH=1Bh 判斷 VGA+;INT 10h AH=4F00h 判斷 VESA 支援;針對 Trident TVGA 9000、Tseng ET6000 等特定晶片組處理分頁暫存器。
  2. 保存視訊狀態:INT 10h AX=1C01h 保存硬體狀態、BIOS 數據區、DAC/調色盤(需 7×64 字節緩衝區)。
  3. 記錄原模式:INT 10h AH=0Fh 取得當前模式號。
  4. 若非文字模式 3/7:
    • 切換至 VGA 基址(0xB8000)並設定分頁暫存器(VESA/Tseng/Trident 專用代碼)。
    • 將可見畫面(文字模式下的 4000 字節,即 80×25×2)從顯存複製到緩衝區(ram_buffer)。
    • 呼叫 INT 10h AX=0083h 設定模式 3(80×25 彩色文字)不清除顯存(AL 位元 7=1)。此時螢幕顯示亂碼,但原圖形畫面實際仍保留在顯存其他分頁/位置。
    • 清除文字模式螢幕(填入空白屬性 0x57B1)。
  5. 若原為文字模式 3/7:直接保存顯存(B8000 或 B0000)至緩衝區,重設模式 3/7 並恢復。

關鍵子程式

1. 顯示卡類型檢測

TEST_VGA PROC
 push 0
 pop ds
 cmp word ptr ds:[33h*4],0
 jz no_mouse
 or cs:flag,10000000b ; has mouse
no_mouse:
 push cs
 pop ds
 mov ah,1bh
 xor bx,bx
 mov di,offset file_end
 int 10h
 cmp al,1bh
 jnz tv_no_vga
 mov ax,4f00h
 mov di,offset file_end
 int 10h
 cmp al,4fh
 jz tv_is_vesa
 ; 檢測 Trident TVGA 9000
 mov dx,3c4h
 mov al,0eh
 out dx,al
 inc dx
 in al,dx
 mov bl,al
 xor al,al
 out dx,al
 in al,dx
 xchg al,bl
 out dx,al
 test bl,2
 jnz tv_is_tvga
 ; 檢測 Tseng ET6000
 mov dx,3cdh
 in al,dx
 mov ah,al
 mov al,11h
 out dx,al
 in al,dx
 xchg ah,al
 out dx,al
 cmp ah,11h
 jz tv_is_tseng
 mov vga_type,4
 ret
tv_is_vesa: mov vga_type,1; ret
tv_is_tvga: mov vga_type,2; ret
tv_is_tseng: mov vga_type,3; ret
tv_no_vga: int 20h
TEST_VGA ENDP

2. 分頁暫存器切換

VGA_PAGE PROC
 cmp vga_type,1 ; VESA
 jnz other_vga1
 cmp ah,1 ; 1=保存 2=恢復
 jz vp_vesa2
 cmp ah,2
 jz vp_vesa1
 mov ax,4f05h
 mov bx,0100h
 int 10h
 mov vga_win1,dx
 mov ax,4f05h
 mov bx,0101h
 int 10h
 mov vga_win2,dx
vp_vesa1:
 mov ax,4f05h
 xor bx,bx
 xor dx,dx
 int 10h
 mov ax,4f05h
 mov bx,0001h
 xor dx,dx
 int 10h
 ret
vp_vesa2:
 mov ax,4f05h
 xor bx,bx
 mov dx,vga_win1
 int 10h
 mov ax,4f05h
 mov bx,0001h
 mov dx,vga_win2
 int 10h
 ret
other_vga1:
 cmp vga_type,3 ; Tseng
 jnz other_vga2
 mov dx,3cdh
 cmp ah,1
 jz vp_tseng2
 cmp ah,2
 jz vp_tseng1
 in al,dx
 mov vga_win3,al
vp_tseng1: xor al,al; out dx,al; ret
vp_tseng2: mov al,vga_win3; out dx,al; ret
other_vga2:
 cmp vga_type,2 ; Trident
 jnz vp_ret
 mov al,0eh; mov dx,03c4h
 cmp ah,1; jz vp_tvga2
 out dx,al; inc dx; in al,dx
 cmp ah,2; jz vp_tvga1
 mov vga_win3,al; xor al,al; out dx,al; ret
vp_tvga1: mov al,2; out dx,al; ret
vp_tvga2: mov ah,vga_win3; out dx,ax; ret
vp_ret: ret
VGA_PAGE ENDP

3. 設定 VGA 基址(解鎖所有顯存平面)

VGA_BASE PROC
 mov dx,3c4h
 mov ax,402h; out dx,ax
 mov ax,704h; out dx,ax
 mov dx,3ceh
 mov ax,0ff08h; out dx,ax
 mov ax,0c06h; out dx,ax
 mov ax,204h; out dx,ax
 mov ax,5; out dx,ax
 ret
VGA_BASE ENDP

4. 保存/恢復螢幕主流程

SAVE_SCR PROC
 push ds; push es
 test flag,10000000b
 jz ss_no_mouse
 mov ax,16h; mov dx,offset mouse_buffer; int 33h ; 保存滑鼠
ss_no_mouse:
 mov ax,1c01h; mov bx,offset video_buffer; mov cx,7; int 10h ; 保存視訊狀態
 mov ah,0fh; int 10h; mov video_mode,al ; 保存原模式
 cmp al,3; jz ss_mode3
 cmp al,7; jz ss_mode7
 xor ax,ax
 call vga_page
 call vga_base
 call save_vram
 mov ax,0083h; int 10h ; 設模式 3 不清顯存
 push 0b800h; pop ds
 xor si,si; mov cx,1000h; mov di,offset ram_buffer
 push cs; push ds; cld; rep movsb ; 保存可見畫面
 xor di,di; mov cx,80*25; mov ax,57b1h; cld; rep stosw ; 清文字螢幕
scr_ret: pop es; pop ds; ret
ss_mode3: call save_vram; jmp scr_ret
ss_mode7: push 0b000h; pop ds; call save_vram1
 mov ax,3; int 10h; call restore_vram; jmp scr_ret
SAVE_SCR ENDP

RESTORE_SCR PROC
 push cs; pop ds
 mov al,video_mode
 cmp al,3; jz rs_mode3
 cmp al,7; jz rs_mode7
 push 0b800h; pop es
 push cs; pop ds
 mov si,offset ram_buffer; xor di,di; mov cx,1000h; cld; rep movsb
 mov ah,2; call vga_page
 call vga_base
 call restore_vram
 xor ah,ah; mov al,video_mode; or al,80h; int 10h ; 恢復原模式不清顯存
 mov ah,1; call vga_base
 jmp rs_mode31
rs_mode3: call restore_vram
rs_mode31:
 push cs; pop es; push cs; pop ds
 mov ax,1c02h; mov bx,offset video_buffer; mov cx,7; int 10h ; 恢復視訊狀態
 test flag,10000000b; jz rs_no_mouse
 mov ax,17h; mov dx,offset mouse_buffer; int 33h ; 恢復滑鼠
rs_no_mouse: ret
rs_mode7: mov ax,7; int 10h
 push 0b000h; pop es; call restore_vram1; jmp rs_mode31
RESTORE_SCR ENDP

適用範圍與限制

  • 適用:保存螢幕後,自身程式僅使用文字模式 3(如彈出文字視窗、選單)。支援所有 VESA 相容顯示卡(PCI/AGP/PCIe 時代均可),唯獨早期 TVGA 9000 因 VESA 實作不完整可能失效。
  • 不適用:若自身程式需進入圖形模式繪圖,仍須完整保存全部顯存(需 XMS/磁碟)。

總結

這個技巧巧妙利用「不清除顯存切換模式」這一鮮為人知的特性,將龐大的圖形顯存問題轉化為僅保存文字模式可見區域(4KB)的輕量操作,極大簡化了 TSR/彈出式工具在圖形環境下的開發難度。它體現了組合語言程式設計師對硬體特性的深度洞察與創造性利用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved