x86实模式显示点阵汉字

设置 显示模式为图形模式,写像素

    mov ax,12h   ;   640x480 16 color graphics (VGA)
    int 10H      ;   Set Video Mode

向显存地址 0xA00000L 里面写一个字节
实模式下,显存需要拆分成段地址 0xa000和偏移 0000 来访问
所有图形方式中显示缓冲区起始地址都是 A000:0000,即 0xA0000000
工作在保护模式,则起址应为 0xA0000;
显示缓冲区长度永远为 0xFFFF 字节, 也就是 内存地址A000:0000到B000:0000为显示存储器,共128KB
直接颜色模式和间接颜色模式(调色板) 对内存的组织是不同的

INT10h 也可以画点(AH=0C, AL=颜色, BH=0, DX=纵坐标,CX=横坐标),BIOS的 INT 10h中画点实现其实也是直接写显存,但是执行的很慢,基本没人这么用,都是直接写显存的,操作显卡除了访问显存外,有些功能还需要访问端口来实现。

设置调色板
256色同屏每个点只有0-255的调色板索引,具体显示什么颜色需要查找一个:256 x 3 = 768 字节的调色板(每个索引3个字节:RGB)。设置一个颜色的调色盘需要先向 0x03c8端口写入颜色编号,接着在 0x03c9端口依次写入R,G,B三个分量的具体数值,具体指令为:

mov edx, 0x03c7
mov al, color
out dx, al
inc dx
mov al, R
out dx, al
mov al, G
out dx, al
mov al, B
out dx, al

x86架构下 OUT 可以向特定端口写入数据,端口你可以理解为和数据总线并立的另外一个 I/O 控制总线,通过北桥南桥映射到各个硬件的 I/O 数据引脚,x86 下通过端口可以方便的操作显卡,软盘,硬盘,8254计时器,键盘缓存,DMA 控制器等周边硬件

显卡发展出VGA模式,显卡的显存也增长到了256KB,而这个时候因为BIOS的东西太多,硬件数量也变多了,已经把D000, E000都占了,此时可用的地址空间只剩下A000,所以A000就用来做VGA的图形模式的显存了。

至此,A0000以后的地址空间就基本确定下来了:

A0000~AFFFF: VGA图形模式显存空间
B0000~B7FFF: MDA单色字符模式显存空间
B8000~BFFFF: CGA彩色字符模式显存空间
C0000~C7FFF: 显卡ROM空间(后来被改造成多种用途,也可以映射显存)
C8000~FFFFE: 留给BIOS以及其它硬件使用(比如硬盘ROM之类的)。

图形模式编程

用int 10h把显卡切换到图形模式

如若要切换到分辨率320*200,颜色为256色的图形模式:

mov ah, 0h

mov al, 13h

int 10h

例如:

mov ax, 0a000h

mov es, ax

mov bx, 0

mov byte ptr es:[bx], 4

一个点只需要填一个字节

(x, y)对应的显卡偏移地址=y*320+x,段地址=A000h

12号 为 640×480 16 color graphics (VGA)
13号模式 为 320×240 256 colors

VGA色彩模式
色彩模式   数据位   同屏颜色数  最大颜色数   亮度级   表示方式
16色       4         16         262144(256K)  64        间接色彩
256色      8         256        262144(256K)  64        间接色彩
15位高彩色  15       不限        32768(32K)   32        直接色彩
16位高彩色  16       不限        65536(64K)  32或64      直接色彩
24位真彩色   24      不限        16777216(16M)   256     直接色彩

对VGA的编程需要结合使用以下三种方式来完成:视频BIOS功能调用、访问显示存储器、寄存器操作

视频BIOS是以中断调用的形式提供的一组软件接口,它对标准VGA的各种功能提供了较全面的支持,但它的图形操作速度太慢且没有提供对VGA扩展特性的支持,因此不能完全依赖此软件接口进行编程,而必须直接与VGA的硬件打交道才能实现有效的图形操作。

要想利用VGA的扩展特性并获得满意的速度,直接访问VGA的显示存储器是实现图形显示的唯一方法,正确访问显示存储器的关键是要搞清VGA显示存储器的结构,而在不同的显示模式下显示存储器都具有不同的组织结构。

在某些显示模式下,访问显示存储器之前必须对VGA的有关状态进行设置,这就需要对VGA的寄存器进行操作。通过寄存器操作还可用硬件实现一些特殊的显示功能。

VGA的显示存储器被映射到主机系统的一段内存地址空间上,这段内存地址称为视频地址,在图形模式下视频地址空间为:A0000H~AFFFFH,这段内存地址在1M以下,因此不论是工作在实模式或是保护模式下的程序都能对这段内存地址进行访问,访问的方法与常规的内存操作完全一样。当向这段视频地址写入数据时,所写的数据即被写到显示存储器上,当从这段地址读数据时,所读出的数据即来自于显示存储器。

显示存储器所能使用的地址空间只有64K,而显示存储器的容量有256K至8M,那么如何通过这段较小的地址空间来访问整个显示存储器呢?VGA采用了两种解决方法:位面技术和显示存储器分页。

1. 位面技术
在位面技术中,VGA将多段大小为64K的显示存储器同时映射到一个64K的视频地址空间上,每段64K的显示存储器即被称为一个位面,当向视频地址写入某个数据时,该数据会被同时写到所有位面上,但是可通过设置VGA的图形控制器及定序器的某些状态,来禁止或允许数据被写到某些位面,并可使所写入的数据只对整个字节中的某一位有效。由此通过一个64K的地址空间即可访问多个64K的显示存储器。

位面技术继承于EGA,它只用在VGA的16色模式中,在其它色彩模式中使用此技术会降低显示存储器的利用率,因此其它色彩模式没有采用位面技术而都采用了存储器分页的方法。

2. 存储器分页
在这种方式下,全部显示存储器被分成若干个64K的段,在某一时刻只有一段显示存储器被映射到视频地址空间上,此时即可对该段显示存储器进行访问,通过某一操作可以改变映射到视频地址空间上的显示存储器段,由此即可实现对所有显示存储器的访问。

每一个64K的显示存储器段称为一页,每页有一个页号,其对应于页在显示存储器中的排列位置,从0开始记数,即第1页的页号为0。改变映射到视频地址空间的显示存储器页的操作,称为换页操作。当前映射到视频地址空间的显示存储器页,称为显示存储器的当前页。

在16色模式中,一个象素占有4位,因此设置有4个位面,这时能同时访问的显示存储器容量为256K,它最大能支持800×600的分辨率,当分辨率进一步提高时,又会出现地址空间上的矛盾,这时就需在位面技术的基础上再采用存储器分页方法,在这种情况下每个存储器页的容量为256K而不是通常的64K,但在一个位面上仍为64K。

存储器分页是一种更直接、更简便且效率更高的方法,但在标准VGA上只有640×480×16色模式存在地址空间的矛盾,而它采用了位面技术来解决,因此在标准VGA上没有提供存储器分页方法,这一方法是在Super VGA上产生的,所以各种型号VGA的分页操作方法都是不一样的,VESA标准提供了分页操作的软件接口,但在直接进行硬件操作时仍然没有标准。

在所有的VGA图形模式下,显示存储器与屏幕象素点之间的映射关系都是线性的,即显示存储器中的每个象素数据按光栅扫描的顺序依次对应于屏幕上的每个象素点。在使用位面技术时,象素在每个位面上各占一个数据位,每位具有相同的地址;在没有采用位面技术时,一个象素点的多个数据位在显示存储器中连续存放,只是在24位色模式下有些特殊。

屏幕坐标原点为屏幕左上角,向右为X轴的正方向,向下为Y轴的正方向。
X,Y象素点在屏幕上的位置;
Width———当前分辨率下的水平象素数;
Height───当前分辨率下的垂直象素数;
BitN———当前色彩模式下每个象素所在显示存储器中所占的二进制位数;
PlaneN───当前色彩模式下所具有的位面数,在没有使用位面技术时,设该数为1;
BitPP———在当前色彩模式下每个象素点在地址空间中所占的二进制位数;
ScanLeng——— 一条扫描线在地址空间中所占用的字节数;
Page───象素点在显示存储器中所处的页;
Offset───象素点在所处页中的地址偏移量;
Bit───象素点在所在字节中所处的位(仅在16色模式有用)。
另有两个在编程中需要考虑的参数:
TotalPage───在当前显示模式下的总页数;
SmSL─── 地址空间尺寸(64K)与ScanLeng相除的余数,当该数等于零时意味着可以整除,该数大于零则意味着不能整除。
上面两个参数可以反映出显示存储器分页的情况,当TotalPage=1时,表示不分页,否则就需要分页,分页又分成两种情况,当SmSL=0时,表示分页只会出现在两条扫描线之间,即行外分页,否则分页就会出现在一条扫描线上,即行内分页。

BitPP=BitN/PlaneN
ScanLeng=Width*BitPP/8 (不适于24位色模式)
Page=(ScanLeng*Y+X*BitPP/8)/10000H
Offset=(ScanLeng*Y+X*BitPP/8)%10000H
Bit=X%8 (只在16色模式下需要)
TotalPage=(ScanLeng*Height-1)/10000H+1
SmSL=10000H%ScanLeng

各种VGA图形模式的地址参数

图形模式            BitN  PlaneN    BitPP    ScanLeng   ToatlPage   分页情况
640×480×16色      4      4         1        80         1           不分页
320×200×256色     8      1         8        320        1           不分页
640×480×256色     8      1         8        640        5           行内分页
640×480×32K色     16     1         16       1280       10          行内分页

在显示存储器中的每个象素点的数据格式随色彩模式的不同而不同

16色模式

在这种色彩模式下,每个象素使用4位数据,这4位数据分别位于处在同一地址的4个位面上。 4个位面的编号为0、1、2、3,它与颜色索引值的4个数据位直接对应,即颜色索引值的位0存于位面0,位1存于位面1,照此类推。

在该模式下,显示存储器中存储的是每个象素点颜色的索引值,4位数据对应有16个不同的颜色索引值,通过两个色彩查找表可确定出每个颜色索引值所对应的真实颜色值。在系统初始化时,这16个索引值对应着一组默认的真实颜色值,如果在程序中不打算修改色彩查找表,就可认为这4位数据定义的是每个象素点的真实颜色值,这时每个数据位的颜色含义如下:
位0———蓝色;
位1———绿色;
位2———红色;
位3———加亮。
这4种状态相互组合即可形成16种真实颜色。

在这种模式下,必须辅以寄存器操作才能有效地读写显示存储器

256色模式

每个象素使用8位数据,1个字节,每个字节连续存放在显示存储器中,这种数据存放方法被称为压缩象素法。
这也是一种间接色彩模式,1个字节对应着256个颜色索引值。在默认状态下,也可认为这一个字节定义着每个象素的真实颜色值,但这时该字节的每个位不存在有规律的基色对应规则。

24位真彩色模式

每个象素使用24位数据,共3个字节。这是一种直接色彩模式,24位数据直接定义着象素点的真实颜色值。
其最高8位数据,即第1个字节,确定蓝色的亮度;
中间8位,即第2个字节,确定绿色的亮度;
最低8位,即第3个字节,确定红色的亮度。
每个基色亮度值的取值范围为:0~255,0为最暗,255为最亮。在这里,三基色的存放顺序与通常的习惯相反。


访问16色模式下的显示存储器、修改色彩查找表及实现一些特殊的显示功能都需要对VGA的寄存器进行操作。

对VGA寄存器的操作通过I/O指令来实现,在汇编语言中用out和in两条指令,在C语言中使用inportb()和outportb()两个函数。

标准VGA包含60多个寄存器,为了避免占用过多的主机I/O地址,VGA的大部分寄存器都采用了一种间接访问方式:将寄存器分为若干组,每组使用两个I/O端口,一个为索引端口,一个为数据端口。每组中的每个寄存器都有一个索引值,通过向索引端口写入一个索引值,来选择一个所要访问的寄存器,然后通过数据端口对所选的寄存器进行读写。在各组寄存器中数据端口的地址都为索引端口的地址加1。对VGA寄存器的操作一般使用8位的I/O指
令,但对这种间接访问方式也可采用16位的I/O指令,即将索引值放在AL中,数据值放在AH中,然后将AX写入索引端口地址,一次完成对那些具有间接访问方式的寄存器的写操作,这种方式速度较快,也较简洁,但某些VGA不支持这种方式。

图形控制器寄存器
这是与16色模式下显示存储器操作密切相关的一组寄存器,它控制着对显示存储器每个位面及一个字节中每一位的访问,并对数据的逻辑运算提供了硬件支持。它包含9个寄存器,其索引端口地址为3CEh,数据端口地址为3CFh。

1. 设置重置寄存器(索引值0)
位:
0写入位面0的数据
1写入位面1的数据
2写入位面2的数据
3写入位面3的数据


对于存储16色(4位)图像,VGA使用的是位平面方式,而DIB采用的是线性方式。无论用哪一种方式,在访问单一像素时,都需要进行复杂的位拆分运算,导致在该色彩模式下很难高效的编程。特别是这两种颜色模式之间的转换,需要极其复杂的位级拆分/重排操作,非常难以高效实现。

为了便于解说,我们将连续的8个像素(从左到右)分别称为A、B、C、D、E、F、G、H。
对描述这些像素的每一位,我们用数字来表示。比如A0代表像素A(从左侧数起:像素0)的第0位(最低位):

Pixel 0: A3 A2 A1 A0
Pixel 1: B3 B2 B1 B0
Pixel 2: C3 C2 C1 C0
Pixel 3: D3 D2 D1 D0
Pixel 4: E3 E2 E1 E0
Pixel 5: F3 F2 F1 F0
Pixel 6: G3 G2 G1 G0
Pixel 7: H3 H2 H1 H0

对于VGA 16色。它使用的是位平面方式,总共4个位平面,一像素的4个位被分别保存在不同的位平面中,即位平面中的一个字节代表了8个像素的一位数据:

[VGA 16色]
Pixel : 0 1 2 3 4 5 6 7
bit  : 7 6 5 4 3 2 1 0
--------------------------------
Plane 0: A0 B0 C0 D0 E0 F0 G0 H0
Plane 1: A1 B1 C1 D1 E1 F1 G1 H1
Plane 2: A2 B2 C2 D2 E2 F2 G2 H2
Plane 3: A3 B3 C3 D3 E3 F3 G3 H3

也就是一个字节中的连续8个bit, 是分别属于8个像素的。

由于切换位平面靠的是慢速的IO端口操作。所以一般是先一次性将整个扫描行的位图数据转成4个位平面数据,再使用串指令分别复制每一位平面的数据。也就是说,当把像素的4个位平面数据分离后,不能直接输出,得写在不同的缓冲区去,还要考虑将位串连接成字节。

在一个16×16的点阵字库中,每个字符的字形数据的长度都为32个字节 (16*16 bits = 32 * 8bits)

每个字符的字形数据都对应于一个固定大小的二值图象,字形数据中的每个二进制位对应于图象上的一个象素点,当字形数据中的某位为1时,该位所对
应的象素点在输出时就应置为指定的字符颜色,否则就保持原色不变.

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注