关键词不能为空

当前您在: 主页 > 英语 >

印度国民大会党30天自制操作系统第8天

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-01-22 16:23
tags:

-

2021年1月22日发(作者:cad是什么)
操作系统实验日志

学号

实验日期

2
2018.11.14
姓名

实验项目

甘昆禄

专业年级班级

智能
1601

8
天:鼠标控制与
32
位模式切换

一、实验主要内容

1.
鼠标解读(
1

已经能从鼠标取得数据了,
紧接着的问题是要解读这些数据,
调查鼠标是怎么移动的,然后结
合鼠标的动作,让鼠标指针相应地动起来。

首先对
bootpa ck.c
中的
HariMain
进行一些修改:


for (;;) {








io_cli();








if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) {












io_stihlt();








} else {












if (fifo8_status(&keyfifo) != 0) {
















i = fifo8_get(&keyfifo);
















io_sti();

















sprintf(s,
















boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
















putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);












} else if (fifo8_status(&mousefifo) != 0) {
















i = fifo8_get(&mousefifo);
















io_sti();
















if (mouse_phase == 0)

/*
等待鼠标的
0xfa
的状态
*/
















{




















if (i == 0xfa)




















{
























mouse_phase = 1;




















}
















} else if (mouse_phase == 1) {




















/*
等待鼠标的第一字节
*/




















mouse_dbuf[0] = i;




















mouse_phase = 2;
















} else if (mouse_phase == 2) {




















/*
等待鼠标的第二字节

*/




















mouse_dbuf[1] = i;




















mouse_phase = 3;
















} else if (mouse_phase == 3) {




















mouse_dbuf[2] = i;




















mouse_phase = 1;




















/*
鼠标的三个字节都齐了,显示出来
*/




















sprintf(s,
mouse_dbuf[2]);




















boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 8 * 8 - 1, 31);




















putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
















}













}








}




}
实际上是将
HariMain

for
循环部分进行修 改,首先把最初读到的
0xfa
舍弃掉。之后,每次
从鼠标那里送过来的数据都应该是
3
个字节一组的,
所以每当数据累积到
3
个字节,
就把他显
示在屏幕上。



%02X
%02X
mouse_dbuf[0],
mouse_dbuf[1],
变量
mouse_phase
用来记住接受鼠标数据的工作进展到了什么阶段
(pha se)
。接受到的数据放

mouse_dbuf[0~2]
内。









if (mouse_phase == 0)

/*
等待鼠标的
0xfa
的状态
*/
















{




















各种处理;






























} else if (mouse_phase == 1) {




















/*
等待鼠标的第一字节
*/




















各种处理
;
















} else if (mouse_phase == 2) {




















/*
等待鼠标的第二字节

*/




















各种处理
;
















} else if (mouse_phase == 3) {




















/*
鼠标的三个字节都齐了,显示出来
*/




















各种处理
;
















}

这部分就是对于不同的
mouse_phase
值,相应地做各种不同的处 理。显示结果如下(鼠标移
动过)



屏幕上除了括号内的还有三 字节数字,即
mouse_dbuf[0],mouse_dbuf[1],mouse_dbuf[2 ]
里的数
据。

08
”部分
0
会在
0~3
的范围内变化,这里鼠标左移时显示
1
,下移时显示
2
,这是演讲的
同学提出的,
湛林莉她观察还真是厉害,
不仅将上下左右,
还把右下、
坐下等也看了出来。

8

只有在点击鼠标时才会有变化,值在
8 ~F
之间。第二个字节与鼠标的左右移动有关,第三个字
节与鼠标的上下移动有关。这里的信息 方便下面为鼠标的动作做出判断。

2.
整理


HariMain
函数中出现的
unsigned char mouse_dbuf[3], mouse_phase;
声明可以放到函数前
的结构体里:

struct MOUSE_DEC {




unsigned char buf[3], phase;
};123

并在这句话修改为:

struct MOUSE_DEC mdec;1
创建的这个结构体
MOUSE_ DEC

DEC

decode
的缩写,用这个结构日把鼠标所需要 的变量都
归总到一块儿。

然后将鼠标的解读从函数
HariMain
的接受信息处理中剥离出来,放到了
mouse_decode
函数。


3.
鼠标解读(
2



struct MOUSE_DEC {




unsigned char buf[3], phase;




int x, y ,btn;
};

int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat)
{




if (mdec->phase == 0) {








/*
等待鼠标的
0xfa
的阶段

*/








if (dat == 0xfa) {












mdec->phase = 1;








}








return 0;




}




if (mdec->phase == 1) {








/*
等待鼠标第一字节的阶段

*/








if ((dat & 0xc8) == 0x08) {












/*
如果第一字节正确
*/












mdec->buf[0] = dat;












mdec->phase = 2;








}








return 0;




}




if (mdec->phase == 2) {








/*
等待鼠标第二字节的阶段

*/








mdec->buf[1] = dat;








mdec->phase = 3;








return 0;




}




if (mdec->phase == 3) {








/*
等待鼠标第三字节的阶段

*/








mdec->buf[2] = dat;








mdec->phase = 1;








mdec->btn = mdec->buf[0] & 0x07;








mdec->x = mdec->buf[1];









mdec->y = mdec->buf[2];








if ((mdec->buf[0] & 0x10) != 0)








{












mdec->x |= 0xffffff00;








}








if ((mdec->buf[0] & 0x20) != 0){












mdec->y |= 0xffffff00;








}








mdec->y = - mdec->y;

/*
鼠标的
y
方向与画面符号相反
*/








return 1;




}




return -1; /*
应该不可能到这里来

*/
}

结构体里增加的几个变量用于存放解读结果,
这几个变量是
x
、< br>y

btn

分别用于存放移动信
息和鼠标按键状态。
if (mdec->phase == 1)
这个语句用于判断第一字节对移动有反应的部分是否< br>在
0~3
的范围内;
同时还要判断第一字节对点击有反应的部分是否在
8~F
的范围内,
如果不在
以上数据范围内就被舍去。
这样做是因为鼠标连线 可能会由接触不良,
这样产生的数据就有错
位,不能顺利解读。
if (mdec->phase == 3)
语句是解读处理的核心。鼠标键的状态放在
buf[0 ]


3
位,我们只取出这
3
位。十六进制的
0x 07
相当于二进制的
0000
0111
,通过与运算
(&)

出低
3
位。
x

y
基本上直接使用
b uf[1]

buf[2]
,但是需要使用第一字节中对鼠标移动有反应
的几 位,将
x

y
的第
8
位及第
8
位以后全部 都设成
1
,或全部都保留为
0
,就能正确解读
x

y
。解读最后对
y
符号进行了取反操作是因为鼠标与屏幕的
y
方向正 好相反,为了配合画面
方向,就对
y
符号进行了取反操作。

鼠标数据解读完成之后接下来修改显示部分:








else if (fifo8_status(&mousefifo) != 0) {
















i = fifo8_get(&mousefifo);
















io_sti();
















if (mouse_decode(&mdec, i) != 0) /*3
字节都凑齐了,所以把它们显示出来
*/
















{




















sprintf(s,




















if (( & 0x01) != 0) {
























s[1] = 'L';




















}




















if (( & 0x02) != 0) {
























s[3] = 'R';




















}




















if (( & 0x04) != 0) {
























s[2] = 'C';




















}




















boxfill8(binfo->vram,
binfo->scrnx,
COL8_008484,
32,
16,
32
+
15
*
8
-
1,
31);




















putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
















}













}

4.
移动鼠标指针

现在就是让鼠标指针在屏幕上动起来啦,感觉好激动,终于能动了(白眼)






else if (fifo8_status(&mousefifo) != 0) {
















i = fifo8_get(&mousefifo);
















io_sti();
















if (mouse_decode(&mdec, i) != 0)

/*3
字节都凑齐了,所以把它们显示出来
*/
















{




















sprintf(s,




















if (( & 0x01) != 0) {
























s[1] = 'L';




















}




















if (( & 0x02) != 0) {
























s[3] = 'R';




















}




















if (( & 0x04) != 0) {
























s[2] = 'C';




















}




















boxfill8(binfo->vram,
binfo->scrnx,
COL8_008484,
32,
16,
32
+
15
*
8
-
1,
31);




















putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);




















/*
鼠标指针的移动
*/









my + 15);




















































































































































































坐标
*/









boxfill8(binfo->vram, binfo->scrnx, COL8_008484, mx, my, mx + 15 * 8 - 1,
/*
隐藏鼠标
*/









mx += mdec.x;









my += mdec.y;









if (mx < x)









{













mx = 0;









}









if (my < 0)









{













my = 0;









}









if (mx > binfo->scrnx - 16)









{













mx = binfo->scrnx - 16;









}









if (my > binfo->scrny - 16)









{













my = binfo->scrny - 16;









}









sprintf(s,









boxfill8(binfo->vram, binfo->scrnx,
COL8_008484,

0,
0,
79,
15);

/*
隐藏
































































putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s);

/*
显示坐

*/




















putfonts8_8(binfo->vram,
binfo->scrnx,
16,
16,
mx,
my,
mcursor,
16);

/*
描画鼠标
*/
















}

先隐藏到鼠标指针,然后根据取得的鼠标数据解读得到的位移量,让鼠标显示在屏幕上。

mx += mdec.x;
my += mdec.y;
是为了防止鼠标指针跑到屏幕外进行的调整。


5.
通往
32
位模式之路

这里讲解了

中的程序。


; PIC
关闭一切中断

;


根据
AT
兼容机的规格,如果要初始化
PIC


;


必须在
CLI
之前进行,否则有时会挂起,

;


随后进行
PIC
的初始化










MOV




AL,0xff








OUT




0x21,AL








NOP




















;
如果连续执行
OUT
指令,有些机种会无法正常运行









OUT




0xa1,AL









CLI




















;
禁止
CPU
级别的中断


这段程序等同于一下内容的
C
程序。


io_out8(PIC0_IMR,

0xff

); /*
禁止主
PIC
的全部中断

*/
io_out8(PIC1_IMR,

0xff

); /*
禁止从
PIC
的全部中断

*/
Io_cli(); /*
禁止
CPU
级别的中断
*/

为了让
CPU
能够访问
1MB
以上的内存空间,设定
A20GATE









CALL



waitkbdout








MOV




AL,0xd1








OUT




0x64,AL








CALL



waitkbdout








MOV




AL,0xdf








; enable A20








OUT




0x60,AL








CALL



waitkbdout1234567

这里的
waitbdout
等同于
wait_KBC_sendr ead
,等同于
C
语言中的:


#define KEYCMD_WRITE_OUTPORT







0xd1
#define KBC_OUTPORT_A20G_ENABLE

0xdf





/* A20GATE
的设定
*/




Wait_KBC_sendready();




Io_out8(PORT_KEYCMD, KEYCMD_WRITE_OUTPORT);




Waite_KBC_sendready();




Io_out8(PORT_KEYDATA, KBC_OUTPORT_A20G_ENABLE);




Waite_KBC_sendready();




/*
这句话是为了等待完成执行指令
*/

程序的基本结构与init_keyboard
完全相同,
功能仅仅是往键盘控制电路发送指令。
这 里发送的
指令,是指令键盘控制电路的附属端口输出
0xdf
。这个附属端口,连接着 主板上的很多地方,
通过这个端口发送不同的指令,就可以实现各种各样的控制功能。


这次输出
0xdf
所要完成的功能,是让
A20GATE
信号线变成
ON
的状态。这条信号线的作用是
使内存的
1MB
以上的 部分变成可使用状态。
Waite_KBC_sendready();
是多余的,在此之后, 虽
然不会往键盘送命令,但仍然要等到下一个命令能够送来为止。这是为了等待
A20GATE
的处
理切实完成。


;
切换到保护模式


[INSTRSET













;
“想要使用
486
指令”的叙述










LGDT



[GDTR0]








;
设定临时
GDT








MOV




EAX,CR0








AND




EAX,0x7fffffff

;

bit31

0
(为了禁止颁)









OR





EAX,0x00000001

;

bit0

1
(为了切换到保护模式)









MOV




CR0,EAX








JMP




pipelineflush
pipelineflush:








MOV




AX,1*8









;

可读写的段

32bit








MOV




DS,AX








MOV




ES,AX








MOV




FS,AX








MOV




GS,AX








MOV




SS,AX

INSTRSET
指令,是为了能够使用
386
以后的
L GDT

EAX


CR0
等关键字。
LGDT< br>指令将暂定的
GDT
读进来。然后将
CR0
这一特殊的
32< br>寄存器的值带入
EAX
,并将最高位置为
0
,最低位置
1

再将这个值返回给
CR0
寄存器。
这样就完成了模式转换,
进入到不用颁的保护模式。
CR0

也就是
control register 0
,是一个非常重要的寄存器,只有操作系统才能操作它。

< br>保护模式是指操作系统受到
CPU
的保护,应用程序既不能随便改变段的设定,又不能使 用操
作系统专用的段。通过带入
CR0
而切换到保护模式时,要马上执行
JM P
指令。因为变成保护
模式后,机器语言的解释要发生变化。
CPU
为了加快 指令的执行速度而使用了管道(
piprline

这一机制。
也就是说,< br>前一条指令还在执行的时候就开始解释下一条甚至再下一条指令。
因为
模式变了,就要重 新解释一遍,所以加入了
JMP
指令。并且在进入保湿模式以后,段寄存器
的意思也变 了
(不再是乘以
16
后再加算的意思了)

除了
CS
以外所有段寄存器的值都从
0x0000
变成了

保持原状是因为如果
CS
也变了,会造成混乱,所以只有
CS
要放到后面再处
理。
0x 0008
,相当于“
gdt+1
”的段。


; bootpack
的传送










MOV




ESI,bootpack



;
传送源









MOV




EDI,BOTPAK





;
传送目的地









MOV




ECX,512*1024/4








CALL



memcpy

;
磁盘数据最终转送到它本来的位置去


;
首先从启动扇区开始










MOV




ESI,0x7c00





;
传送源









MOV




EDI,DSKCAC





;
传送目的地









MOV




ECX,512/4








CALL



memcpy

;
所有剩下的










MOV




ESI,DSKCAC0+512
传送源









MOV




EDI,DSKCAC+512

;
传送目的地









MOV




ECX,0








MOV




CL,BYTE [CYLS]








IMUL



ECX,512*18*2/4

;
从柱面数变换为字节数
/4








SUB




ECX,512/4






;
减去
IPL








CALL



memcpy

这部分程序只是在调用
memcpy
函数,
同样可以理解成
C
语言形式
(写法可能不正确,
但中心
思想是类似 的)


memcpy(bootpack,









BOTPAK,









512*1024/4);
memcpy(0x7c00,













DSKCAC,









512/4










);
memcpy(DSKCAC0+512, DSKCAC+512, cyls*512*18*2/4 - 512/4);

函数
mencpy
是赋值内存的函数,语法如下:


memcpy(
转送源地址
,


转送目的地址
,

转送数据的大小
);

转送数据大小是以双字节位单位的,所以数据大小用字节数除以
4
来指定。


memcpy(0x7c00, DSKCAC, 512/4);

D SKCAC

0x00100000
,所以上面这句话就是从
0x7c00< br>复制
512
字节到
0x00100000
。这正好
是将启动扇 区复制到
1MB
以后的内存去。


memcpy(DSKCAC0+512, DSKCAC+512, cyls*512*18*2/4 - 512/4);

它的意思是将始于
0x0 0008200
的磁盘内容,复制到
0x00100200
那里。

上文中“转送数据大小”的计算有点复杂,因为它是以柱面数来计算的,所以需要减去启动区
的那一部分 长苏。
IMUL
是乘法运算,
SUB
是减法运算。

boo tpack

asmhead,nas
的最后一个标签,

连接起来而 生成的,所以
asmhead

束的地方,紧接着串联着

最前面的部 分。

memcpy(bootpack, BOTPAK, 512*1024/4);

→从
bootpack
的地址开始的
512KB
内容复制 到
0x00280000
号地址去


;
必须有
asmhead
来完成的工作,至此全部完毕

;


以后就变由
bootpack
来完成


; bootpack
的启动

-


-


-


-


-


-


-


-



本文更新与2021-01-22 16:23,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/550421.html

30天自制操作系统第8天的相关文章

  • 爱心与尊严的高中作文题库

    1.关于爱心和尊严的作文八百字 我们不必怀疑富翁的捐助,毕竟普施爱心,善莫大焉,它是一 种美;我们也不必指责苛求受捐者的冷漠的拒绝,因为人总是有尊 严的,这也是一种美。

    小学作文
  • 爱心与尊严高中作文题库

    1.关于爱心和尊严的作文八百字 我们不必怀疑富翁的捐助,毕竟普施爱心,善莫大焉,它是一 种美;我们也不必指责苛求受捐者的冷漠的拒绝,因为人总是有尊 严的,这也是一种美。

    小学作文
  • 爱心与尊重的作文题库

    1.作文关爱与尊重议论文 如果说没有爱就没有教育的话,那么离开了尊重同样也谈不上教育。 因为每一位孩子都渴望得到他人的尊重,尤其是教师的尊重。可是在现实生活中,不时会有

    小学作文
  • 爱心责任100字作文题库

    1.有关爱心,坚持,责任的作文题库各三个 一则150字左右 (要事例) “胜不骄,败不馁”这句话我常听外婆说起。 这句名言的意思是说胜利了抄不骄傲,失败了不气馁。我真正体会到它

    小学作文
  • 爱心责任心的作文题库

    1.有关爱心,坚持,责任的作文题库各三个 一则150字左右 (要事例) “胜不骄,败不馁”这句话我常听外婆说起。 这句名言的意思是说胜利了抄不骄傲,失败了不气馁。我真正体会到它

    小学作文
  • 爱心责任作文题库

    1.有关爱心,坚持,责任的作文题库各三个 一则150字左右 (要事例) “胜不骄,败不馁”这句话我常听外婆说起。 这句名言的意思是说胜利了抄不骄傲,失败了不气馁。我真正体会到它

    小学作文