相比前几篇的内容,本篇不仅内容更为简单,而且与显示相关,更为有趣。首先通过调用VBE的显示模式提高显示画面的分辨率,然后分别实现按下键盘按键显示对应的字符,以及通过鼠标移动窗口。因为是以前面讲过的很多内容为基础,程序代码很简单,而且能切实看到成果,也更有趣。
1. 提高画面分辨率
现在要把显示画面的分辨率提高到640x480,就又要修改BIOS的画面模式设定所用的汇编语言代码了。
; 设定画面模式
MOV BX,0x4101 ; VBE的640x480x8bit彩色
MOV AX,0x4f02
INT 0x10
MOV BYTE [VMODE],8 ; 记录下画面模式
MOV WORD [SCRNX],640
MOV WORD [SCRNY],480
MOV DWORD [VRAM],0xe0000000
记得之前切换画面模式用的汇编语言指令是“AH = 0, AL = 画面模式号码”,但是上面这段代码却有所不同,用的是AX = 0x4f02。这是什么原因呢?
从前电脑的规格是以IBM公司为中心决定的,IBM规定了画面显示模式的规格,各家显卡公司也按照这一规格来进行实现。而后来各个显卡公司开发出了更多性能更好的显卡,具有各种画面显示模式,设置和使用的方法也各不相同,导致程序员比较无所适从。于是多家显卡公司进行协商,成立了VESA协会。这个协会制定了几乎可以通用的设置方法,制作了专门的BIOS,这个追加的BIOS被称为VESA BIOS extension,简称为VBE。利用它就可以扩展显卡的显示模式了。
VBE的画面模式号码如下:
- 0x101: 640x480x8bit 彩色
- 0x103: 800x600x8bit 彩色
- 0x105: 1024x768x8bit 彩色
- 0x107: 1280x1024x8bit 彩色
为了在真机上使用VBE的显示模式,我们还需要进行一些确认。
(1) 确认是否支持VBE?
有些公司的产品仍然不支持VBE,因此无法使用VBE的显示模式。我们通过如下操作来进行确认:
; 确认VBE是否存在
MOV AX,0x9000
MOV ES,AX
MOV DI,0
MOV AX,0x4f00
INT 0x10
CMP AX,0x004f
JNE scrn320
这里给ES赋值0x9000,给DI赋值为0,给AX赋值为0x4f00,再执行INT 0x10,如果有VBE的话,AX就会变成0x004f。否则说明没有VBE,仍然只能使用之前320x200的画面。而为ES和DI进行赋值,是因为此显卡能利用的VBE信息将要写入内存中以ES:DI开始的512字节中。
(2) 确认VBE的版本是否在2.0以上
使用高分辨率,也需要VBE的版本在2.0以上。
; VBE版本确认
MOV AX,[ES:DI+4]
CMP AX,0x0200
JB scrn320 ; if (AX < 0x0200) goto scrn320
(3) 即使VBE版本在2.0以上,也还是需要确认画面模式0x105是否能够使用:
; 获取画面模式信息
MOV CX,VBEMODE
MOV AX,0x4f01
INT 0x10
CMP AX,0x004f
JNE scrn320
这里对AX的值进行了确认,如果是0x004f以外的值,所指定的画面模式就不能使用。
此次取得的画面模式信息也被写入内存从ES:DI开始的256字节中,这样刚才VBE的版本信息会被覆盖。但确认VBE版本之后这个信息就不需要了,因此没什么影响。
(4) 其他画面模式信息确认
这还没完,还有最后的几项信息需要确认:
- 颜色数是否为8
- 是否为调色板模式
- 画面模式号码是否可以加上0x4000再进行指定
; 画面模式信息确认
CMP BYTE [ES:DI+0x19],8
JNE scrn320
CMP BYTE [ES:DI+0x1b],4
JNE scrn320
MOV AX,[ES:DI+0x00]
AND AX,0x0080
JZ scrn320 ; 模式属性的bit7是0,放弃
以上这些信息如果都确认OK,那么就可以使用VBE的画面模式了。如果确认不通过,则还是只能使用之前的分辨率。
; 画面模式切换
MOV BX,VBEMODE+0x4000
MOV AX,0x4f02
INT 0x10
MOV BYTE [VMODE],8 ;
MOV AX,[ES:DI+0x12]
MOV [SCRNX],AX
MOV AX,[ES:DI+0x14]
MOV [SCRNY],AX
MOV EAX,[ES:DI+0x28]
MOV [VRAM],EAX
JMP keystatus
scrn320:
MOV AL,0x13 ; VGA图,320x200x8bit彩色
MOV AH,0x00
INT 0x10
MOV BYTE [VMODE],8 ;
MOV WORD