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

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

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

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

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

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

对VGA的读操作

首先,我们还是要计算点在内存中的位置。由于我们在上一章已经介绍过了。所以,这里我们就不多做解释了。直接写出代码。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;文件名: VGA_READ.ASM(部分解析)
;;作者: 黄庠魁
;;主要函数:Pix_read
;;参数说明: 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)黄庠魁
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

上面的代码其实就是抄袭了(1)的代码,这里再写一遍是为了没有读(1)的读者考虑。

然后,我们还是要在八个二进制中,找到我们要的指定象素。不同的是这次我们要选择一个比较有效的方式。而且,我们要保护y内的偏移量,便于我们以后再次使用。有关16色的工作原理,我想我们就不要再温习了。所以,我们就直接切入正题。

现在,假设你已经知道锁存,位面的关系。那么,我们要考虑如何将一些支离破碎的颜色组合起来。下面我们先来确定读取象素的位置。所以,我们给出了(1)中相同的代码。不同的是,我们在后面的使用方式不同。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;文件名: VGA_READ.ASM(部分解析)
;;作者: 黄庠魁
;;主要函数:Pix_read
;;参数说明: 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)黄庠魁
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

记得,上面的y和b内的内容。我后面要使用他们来做一个相对效率较高的运算。如果,各位有更好更快更稳定的方式,记得一定要告诉我!记得!

最后,我就要读出内存中的颜色信息了。大家知道,颜色的四位是分别在四个锁存内的。所以,我们要对同一地址读四次才能获得。而每次读出会有一个字,也就是八个象素的四分之一。我们将用test 也就是 and (逻辑乘,也叫与)来获得。然后,用or(逻辑加,也叫或)来读入临时的寄存器。下面我们废话少说,来动手做吧。我们会用读模式0来完成读操作。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;文件名: VGA_READ.ASM(部分解析)
;;作者: 黄庠魁
;;主要函数:Pix_read
;;参数说明: cx : x坐标值 dx : y坐标值 返回:al : 颜色值(16色)
;;简要注意: 本程序需要用户在VGA 640*380 16色模式下工作,在使用前,请使用BIOS中断
;; 设置VGA显示模式为 12H。
;;创建时间: 2005年1月
;;CopyRight: (C)黄庠魁
;;邮箱:[email protected]
;;产权所有 不得抄袭 如要使用 与我联系
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;接上面的代码,x是地址,y是位移数,b是数据
push bx
push cx
push dx
push es
push ax;保存现场数据,虽然al是修改的,但是ah要恢复的^_^
mov ax,0a000h ;设置es的地址为 0a000h
mov es,ax

;我们要设置模式寄存器内为读模式0
mov dx,3ceh
mov al,5h
out dx,al ;设置当前有效寄存器为 模式寄存器

mov dx,3cfh
mov al,00000000b
out dx,al ;设置当前读模式为0,注意,读模式和写模式设置的位不同,详情看(1)

;我们要在读数据前,设置初始化操作
mov bx,word[x] ;这是设置内存中的位置。
mov ah,00000000b ;这里设置ah为00000000b 由于后面的一些操作不会用到ah所以,可以用它做临时的寄存器

mov dx,3ceh
mov al,4h
out dx,al ;设置当前使用 读位面选择寄存器

;下面我们要开始读数据了
;第一次读
mov dx,3cfh
mov al,03h
out dx,al ;当前读取 位面3

mov al,byte[es:bx] ;读取数据
and al,byte[b] ;取出我们要的位的二进制数据
or ah,al ;将数据读入临时寄存器 ah
rol ah,1 ;循环左移一个ah
;第二次读
mov dx,3cfh
mov al,02h
out dx,al ;当前读取 位面2

mov al,byte[es:bx] ;读取数据
and al,byte[b] ;取出我们要的位的二进制数据
or ah,al ;将数据读入临时寄存器 ah
rol ah,1 ;循环左移一个ah
;第三次读
mov dx,3cfh
mov al,01h
out dx,al ;当前读取 位面1

mov al,byte[es:bx] ;读取数据
and al,byte[b] ;取出我们要的位的二进制数据
or ah,al ;将数据读入临时寄存器 ah
rol ah,1 ;循环左移一个ah
;第四次读
mov dx,3cfh
mov al,00h
out dx,al ;当前读取 位面0

mov al,byte[es:bx] ;读取数据
and al,byte[b] ;取出我们要的位的二进制数据
or ah,al ;将数据读入临时寄存器 ah
rol ah,1 ;循环左移一个ah

;最后,我们要整理数据了,好让它输出成我们要的数据

mov cx,word[y]
rol ah,cl ;在刚才我们右移y位,现在我们再移回来

mov al,ah ;将数据保存入al,便于数据返回。
pop bx ;恢复ax的数据。
mov ah,bh ;将ah内的数据恢复了

pop es
pop dx
pop cx
pop bx ;恢复数据

;到这里,程序算是完成了
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;CopyRight: (C)黄庠魁
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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

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

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

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

mov bx,word[x]
mov ah,00000000b

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

mov dx,3cfh
mov al,03h
out dx,al

mov al,byte[es:bx]
and al,byte[b]
or ah,al
rol ah,1

mov dx,3cfh
mov al,02h
out dx,al

mov al,byte[es:bx]
and al,byte[b]
or ah,al
rol ah,1

mov dx,3cfh
mov al,01h
out dx,al

mov al,byte[es:bx]
and al,byte[b]
or ah,al
rol ah,1

mov dx,3cfh
mov al,00h
out dx,al

mov al,byte[es:bx]
and al,byte[b]
or ah,al
rol ah,1

mov cx,word[y]
rol ah,cl

mov al,ah
pop bx
mov ah,bh

pop es
pop dx
pop cx
pop bx

;S3 End

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

我这次使用的工具,想和大家分享一下。我使用的是Emacs编译,NASM编译。不错的。可以在Win32和Linux下用。感觉非常不错。如果各位有兴趣,也可以用用看。虽然,Emacs上手比较难,但是,知道一些基本操作后,你会发现它有多么迷

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

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