VGA显示卡图形模式访问(提示版) (1)

VGA显示卡图形模式访问(提示版) (1)

最近闲来无聊,在 上海图书馆 借了本《IBM-PC汇编语言程序设计》。没想,在看显示器访问的那章时。觉得作者讲得实在含糊,无法让人明白。后来,又借了本《80x86汇编语言程序设计》发现,这两本书在那一章节的内容几乎是一样,例子图片都一样。在我反复的摸索和在 上海科学技术情报研究所 里查看几天的资料后。终于模清了门路。当然,我也上网看了。没有相关的内容,也许是我没找到。所以,在这里献上我的成果希望有缘人能和我交流。

本文主要是介绍不用BIOS中断在VGA 640*480 16色模式下,对屏幕单个象素进行读写操作。我将用两段代码来说明如何操作,用于对各位处于迷茫的学者们一些提示。

在阅读本文前,我希望读者能够有一定的汇编基础,和对VGA显卡原理的基础知识(其实只要知道一些就可以了)。如果有空,可以在看本文之前阅读前面我借的两本书中的一本中,有关VGA显示卡的操作内容。

本文使用的例子,是用于NASM汇编器,读者可以从网上免费下载。我使用的软件,都可以从www.sf.net免费下载。

对VGA的写操作

首先是确定坐标位置,由于对内存的访问是一个字节,也就是 8 位二进制,而四个位面同一地址的字,构成了一个四位的颜色值。所以,我们需要确定在0a000h中的哪段地址进行操作。

b=x/8+y*80

既然知道如何计算所写的位置,我们就来写一段汇编代码。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;文件名: VGA_WRITE.ASM(部分解析)
;;作者: 黄庠魁
;;主要函数:Pix_write
;;参数说明: cx : x坐标值 dx : y坐标值 al : 颜色值(16色)
;;简要注意: 本程序需要用户在VGA 640*380 16色模式下工作,在使用前,请使用BIOS中断
;; 设置VGA显示模式为 12H。
;;创建时间: 2005年1月
;;CopyRight: (C)黄庠魁
;;邮箱:[email protected]
;;产权所有 不得抄袭 如要使用 与我联系
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;x=cx,y=dx
push ax ;保存现场AX寄存器
push bx ;保存现场BX寄存器
push dx ;保存现场DX寄存器

;开始计算x/8
mov ax,cx
mov bx,8
div bl ;al=ax/8 ah=ax%8
mov word[x],ax ;将结果存入x

;开始计算y*80
pop ax ;将dx的内容读入ax
push ax;将ax内容入栈,以便在程序结束后恢复dx内容
mov bx,80
mul bx ;(dx,ax)=ax*80。因为dx在这个计算中不会有值,所以dx不作记录。
mov word[y],ax

;开始汇总计算
mov ax,word[x]
mov dx,word[y]

mov bl,al
mov bh,00h ;这里我们要将8位扩展成16位

add dx,bx ;dx+bx

mov word[x],dx
mov al,ah
mov ah,00h ;扩展成16位
mov word[y],ax

;恢复数据
pop dx
pop bx
pop ax

x: dw 0
y: dw 0
;程序运行完成,x中的内容为访问地址,y为偏移量
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;CopyRight: (C)黄庠魁
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

刚才的程序运行后,我们能通过写 0a000:x 的值来修改屏幕的象素。

然后,我们来看如何写。对于图形控制寄存器组,我这里不做介绍了。大家可以从书上看到,到处都是。

由于0a000:x中有八个象素的值,所以,为了能确定其中一个象素,我们必须使用刚才计算的y来将所给的数据进行偏移。

那么如果,偏移量是0说明是地址的开始位置,也就是10000000b。如果不是,那么如果是2,数据就是00100000b。所以,我们就可以知道如何在8个象素中确定其中一个象素。

照例,我们写一段代码

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;文件名: VGA_WRITE.ASM(部分解析)
;;作者: 黄庠魁
;;主要函数:Pix_write
;;参数说明: cx : x坐标值 dx : y坐标值 al : 颜色值(16色)
;;简要注意: 本程序需要用户在VGA 640*380 16色模式下工作,在使用前,请使用BIOS中断
;; 设置VGA显示模式为 12H。
;;创建时间: 2005年1月
;;CopyRight: (C)黄庠魁
;;邮箱:[email protected]
;;产权所有 不得抄袭 如要使用 与我联系
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;接着上面的代码,在b中存放写入的数据
push ax ;保护现场ax入栈
push cx ;保护现场bx入栈

mov cx,word[y] ;将偏移量入cx
mov al,10000000b ;由于一个字八位,所以就只使用al
ror al,cl ;这里由于只有一个1,所以ror和shr都是一样的
mov byte[b],al ;将返回的数据存入 b

;恢复现场
pop cx
pop ax

b: db 0

;程序运行完成,b中的内容为写入的数据位置。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;CopyRight: (C)黄庠魁
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

最后,我们要来完成写入工作了。

对于写,我个人觉得书上说的很不清楚,因为,位屏蔽寄存器是需要读锁存的。然而,前面对VGA的工作原理没有详细的介绍。造成后面对位屏蔽的错误理解。
由于锁存是需要读入的,所以,在每次写操作前要使用位屏蔽必须先读一次。将数据写入锁存以便后面使用。

对于颜色的设置,我们可以通过 设置重置寄存器 和 设置重置允许寄存器 来完成。

设置重置寄存器 索引 0h
位: 0 写入位面0的数据
位: 1 写入位面1的数据
位: 2 写入位面2的数据
位: 3 写入位面3的数据
位 4~7 保留

设置重置允许寄存器 索引 1h
位: 0 位面0设置重置允许
位: 1 位面1设置重置允许
位: 2 位面2设置重置允许
位: 3 位面3设置重置允许
位:4~7 保留

下面,我们就来看看写的例子。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;文件名: VGA_WRITE.ASM(部分解析)
;;作者: 黄庠魁
;;主要函数:Pix_write
;;参数说明: cx : x坐标值 dx : y坐标值 al : 颜色值(16色)
;;简要注意: 本程序需要用户在VGA 640*380 16色模式下工作,在使用前,请使用BIOS中断
;; 设置VGA显示模式为 12H。
;;创建时间: 2005年1月
;;CopyRight: (C)黄庠魁
;;邮箱:[email protected]
;;产权所有 不得抄袭 如要使用 与我联系
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;还是接着上面的例子。
;al是显示的颜色

push dx ;保存现场dx数据

push ax ;保存用户输入的颜色信息

;对图形控制器寄存器操作
;设置写模式
mov dx,3ceh
mov al,5h
out dx,al ;设置使用 模式寄存器

mov dx,3cfh
mov al,00000000b
out dx,al ;设置使用 写模式0 位:0~1 写模式(0,1,2,3) 使用 读模式0 位:3 读模式(0,1)

;设置重置允许寄存器
mov dx,3ceh
mov al,1h
out dx,al ;设置使用 重置允许寄存器

mov dx,3cfh
mov al,0fh
out dx,al ;由于我们要全部使用寄存器的内容,而且是16色所以设置成0fh

;设重置寄存器
mov dx,3ceh
mov al,0h
out dx,al ;设置使用 重置寄存器

mov dx,3cfh
pop ax 读出用户颜色信息
push ax 保存用户信息,便于以后恢复
out dx,al ;这里我们的颜色设置好了,所以,在后面的内存操作中就可以随便写入了。

;设置数据循环位移寄存器
mov dx,3ceh
mov al,3h
out dx,al ;设置使用 数据循环位移寄存器

mov dx,3cfh
mov al,00000000b
out dx,al ;由于我们在开始的时候就已经循环好了,所以统统设成0。而且这个循环只对CPU使用,我们用的是寄存器。

;设置位屏蔽寄存器
mov dx,3ceh
mov al,8h
out dx,al ;设置使用 位屏蔽寄存器

mov dx,3cfh
mov al,byte[b]
out dx,al ;我们这里使用屏蔽,将不需要设置的内容去掉。

;设置数据段和初始参数
mov ax,0a000h
mov es,ax
mov bx,word[x]

;因为我们只是让VGA读一次现存。所以,我们就听天由命的读一次内存吧,反正我们也不用这个参数。
mov dx,3ceh
mov al,4h
out dx,al ;设置当前可用寄存器为 读位面选择寄存器

mov dx,3cfh
mov al,00h
out dx,al
mov al,byte[es:bx] ;让锁存读取 位面0 的数据

mov dx,3cfh
mov al,01h
out dx,al
mov al,byte[es:bx] ;让锁存读取 位面1的数据

mov dx,3cfh
mov al,02h
out dx,al
mov al,byte[es:bx] ;让锁存读取 位面2的数据

mov dx,3cfh
mov al,03h
out dx,al
mov al,byte[es:bx] ;让锁存读取 位面3的数据

;然后我们就来进行写了。
mov al,00h
mov byte[es:bx],al
;因为这里我们的CPU数据不会对色彩有任何影响,因为前面已经设置成使用重置寄存器了。所以这里就写个00h进去吧。

;恢复现场数据
pop ax
pop dx

;到这里,所有的写操作算是完成了。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;CopyRight: (C)黄庠魁
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

下面,我就把完成的子程序代码贴出来。其实,就是上面三组代码的整合。(听起来像IBM说的“整合”)。不过这里注释就不加了,因为上面都有了。
下面这段代码在Nasm下编译成功,并且运行良好。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;文件名: VGA_WRITE.ASM
;;作者: 黄庠魁
;;主要函数:Pix_write
;;参数说明: cx : x坐标值 dx : y坐标值 al : 颜色值(16色)
;;简要注意: 本程序需要用户在VGA 640*380 16色模式下工作,在使用前,请使用BIOS中断
;; 设置VGA显示模式为 12H。
;;创建时间: 2005年1月
;;CopyRight: (C)黄庠魁
;;邮箱:[email protected]
;;产权所有 不得抄袭 如要使用 与我联系
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Pix_write:
;S1 Start

push ax
push bx
push dx

mov ax,cx
mov bx,8
div bl
mov word[x],ax

pop ax
push ax
mov bx,80
mul bx
mov word[y],ax

mov ax,word[x]
mov dx,word[y]
mov bl,al
mov bh,00h
add dx,bx

mov word[x],dx

mov al,ah
mov ah,00h
mov word[y],ax

pop dx
pop bx
pop ax

;S1 End

;S2 Start

push ax
push cx

mov cx,word[y]
mov al,10000000b
ror al,cl
mov byte[b],al

pop cx
pop ax

;S2 End

;S3 Start

push dx
push ax

mov dx,3ceh
mov al,5h
out dx,al

mov dx,3cfh
mov al,00000000b
out dx,al

mov dx,3ceh
mov al,1h
out dx,al

mov dx,3cfh
mov al,0fh
out dx,al

mov dx,3ceh
mov al,0h
out dx,al

mov dx,3cfh
pop ax
push ax
out dx,al

mov dx,3ceh
mov al,3h
out dx,al

mov dx,3cfh
mov al,00000000b
out dx,al

mov dx,3ceh
mov al,8h
out dx,al

mov dx,3cfh
mov al,byte[b]
out dx,al

mov ax,0a000h
mov es,ax

mov bx,word[x]

mov dx,3ceh
mov al,4h
out dx,al

mov dx,3cfh
mov al,00h
out dx,al
mov al,byte[es:bx]

mov dx,3cfh
mov al,01h
out dx,al
mov al,byte[es:bx]

mov dx,3cfh
mov al,02h
out dx,al
mov al,byte[es:bx]

mov dx,3cfh
mov al,03h
out dx,al
mov al,byte[es:bx]

mov al,00h
mov byte[es:bx],al

pop ax
pop dx

;S3 End

ret


x: dw 0
y: dw 0
b: db 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;CopyRight: (C)黄庠魁
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

STUDIO软件开发组(SDT)
STUDIO Development Team
北斗星君(黄庠魁)
2005年1月

你可能感兴趣的:(设计模式,C++,c,IBM,C#)