Day14
今天继续补全了昨天的性能测试,还有提高分辨率,把键盘、鼠标传来的中断信息转换为我们可以直接理解的信息。
一些感想
很细致的对比实验
昨天作者测试性能的时候,因为担心初始化带来的影响,去掉了初始化。今天作者因为担心JMP到不同地址带来的影响,加了一个函数的空操作。不得不说作者知识面很广,而且这种问题也可以考虑到。。
提高分辨率的方法
我们在asmhead.nas的显卡设置那一部分,可以调整VBE的参数设置,于是就可以调用不同分辨率的显卡。
对于较高分辨率的显卡,BX = 模式设定 + 0x4000,AX = 0x4f02。这样才能正确设定显卡。
0x101·······640*480*8bit彩色
0x103·······800*600*8bit彩色
0x105·······1024*768*8bit彩色
0x107·······1280*1024*8bit彩色(对于QEMU来说不可用)
当然,不是所有显卡都能提升成这样的分辨率,所以需要先通过测试代码,来看到底支不支持。
另外,书中提到了画面模式信息的获取方法:
键盘输入
查文档、查表可以得到键盘对应的中断数值,具体与哪个键对应(当然也可以自己一个键一个键按。。)。那么我们也可以因此来做一个键盘中断信息与字符对应的表。
不过目前的程序还不能对shift、ctrl等组合键作出判断。
鼠标输入
将对应的鼠标信息解码,配合上一些逻辑操作,就可以比如——移动窗口了。
进入正文
继续测试性能
harib11a
harib11b
harib11c
作者把昨天的数组、链表、链表+哨兵三个版本做了一下性能测试,同时设定了大量的计时器,来比较性能到底有没有提升。
结果发现,链表+哨兵会有略微的提升,如果追求极致的话这样也算挺不错了。不过这个提升甚至没有JMP地址带来的影响大。。
提高分辨率
harib11d
回到了汇编,改写画面模式设定
; 画面模式设定
MOV BX,0x4105 ; VBE的1024*768*8bit彩色
MOV AX,0x4f02
INT 0x10
MOV BYTE [VMODE],8 ; 记下画面模式(参考C语言)
MOV WORD [SCRNX],1024
MOV WORD [SCRNY],768
MOV DWORD [VRAM],0xe0000000
0x101 0x103 0x105 随便选。。BX和AX里的数,是赋值规定要求这么做的。
提高分辨率(2)
harib11e
这一节主要是为了检测兼容性:是否支持VBE标准,以及是否支持高分辨率的显卡。
; 确认VBE是否存在
MOV AX,0x9000
MOV ES,AX
MOV DI,0
MOV AX,0x4f00
INT 0x10
CMP AX,0x004f
JNE scrn320
前面这5条指令下来,如果有VBE,则AX就会变为0x004f。没有的话就只能使用scrn320了
; 检查VBE的版本
MOV AX,[ES:DI+4]
CMP AX,0x0200
JB scrn320 ; if (AX < 0x0200) goto scrn320
VBE的版本如果不是2.0以上,仍然不能使用高分辨率
; 取得画面模式信息
MOV CX,VBEMODE
MOV AX,0x4f01
INT 0x10
CMP AX,0x004f
JNE scrn320
VBEMODE是我们预先制定好的想要设置到的模式。如果AX不等于0x004f,就意味着该模式不可用
; 画面模式信息的确认
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,所以放弃
进行一系列确认之后,调成高分辨率:
; 画面模式的切换
MOV BX,VBEMODE+0x4000
MOV AX,0x4f02
INT 0x10
MOV BYTE [VMODE],8 ; 记下画面模式(参考C语言)
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
如果失败了,就只能JMP scrn320,使用老的设定。
键盘输入(1)
harib11f
先尝试对一个字符作出正确的响应:
if(256 <= i && i <= 511) // 键盘数据
{
sprintf(s, "%02X", i - 256);
putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
if(i == 0x1e + 256)
{
putfonts8_asc_sht(sht_win, 40, 28, COL8_000000, COL8_C6C6C6, "A", 1);
}
}
这样应该没什么问题。很容易显示。
键盘输入(2)
harib11g
建立一张对应的表(数组):
static char keytable[0x54] = {
0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0, 0,
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0, 0, 'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1',
'2', '3', '0', '.'
};
不过这张表里,是日式键盘的对应规则,例如 ‘[‘ 、’]’ 、’\’ 都没有做到正确的对应,不过等到以后系统成熟的时候,再修改这些吧。
字符的显示:
if(256 <= i && i <= 511) // 键盘数据
{
sprintf(s, "%02X", i - 256);
putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
if(i < 256 + 0x54)
{
if(keytable[i - 256] != 0)
{
s[0] = keytable[i - 256];
s[1] = 0;
putfonts8_asc_sht(sht_win, 40, 28, COL8_000000, COL8_C6C6C6, s, 1);
}
}
}
追记内容(1)
harib11h
加一个可以输入信息的窗口。
主函数里:
make_textbox8(sht_win, 8, 28, 144, 16, COL8_FFFFFF);
cursor_x = 8;
cursor_c = COL8_FFFFFF;
键盘FIFO接收部分:
if(256 <= i && i <= 511) // 键盘数据
{
sprintf(s, "%02X", i - 256);
putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
if(i < 0x54 + 256)
{
if(keytable[i - 256] != 0 && cursor_x < 144) // 一般字符
{
// 显示1个字符,就向前移动1个光标
s[0] = keytable[i - 256];
s[1] = 0;
putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1);
cursor_x += 8;
}
}
if(i == 256 + 0x0e && cursor_x > 8) // 退格键
{
// 用空格键把光标消去后,后移1次光标
putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1);
cursor_x -= 8;
}
// 光标再显示(这样就覆盖住了刚才的文字)
boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43);
sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44);
}
新增函数,描绘文字的输入背景(绘制那个窗口的意思)
void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c)
{
int x1 = x0 + sx, y1 = y0 + sy;
boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3);
boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1);
boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2);
boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2);
boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2);
boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0);
boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1);
boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1);
boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0);
return;
}
追记内容(2)
harib11i
鼠标点哪里,中间的窗口就会去哪里:
鼠标FIFO接收部分:
if((mdec.btn & 0x01) != 0)
{
// 按下左键、移动sht_win
sheet_slide(sht_win, mx - 80, my - 8);
}