30天自制操作系统第8天(共27页).docx

上传人:飞****2 文档编号:14014097 上传时间:2022-05-02 格式:DOCX 页数:27 大小:1.88MB
返回 下载 相关 举报
30天自制操作系统第8天(共27页).docx_第1页
第1页 / 共27页
30天自制操作系统第8天(共27页).docx_第2页
第2页 / 共27页
点击查看更多>>
资源描述

《30天自制操作系统第8天(共27页).docx》由会员分享,可在线阅读,更多相关《30天自制操作系统第8天(共27页).docx(27页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、精选优质文档-倾情为你奉上操作系统实验日志学号姓名甘昆禄专业年级班级智能1601实验日期2018.11.14实验项目第8天:鼠标控制与32位模式切换一、实验主要内容1. 鼠标解读(1)已经能从鼠标取得数据了,紧接着的问题是要解读这些数据,调查鼠标是怎么移动的,然后结合鼠标的动作,让鼠标指针相应地动起来。首先对bootpack.c中的HariMain进行一些修改:for (;) io_cli(); if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) = 0) io_stihlt(); else if (fifo8_status(&keyfi

2、fo) != 0) i = fifo8_get(&keyfifo); io_sti(); sprintf(s, %02X, i); boxfill8(binfo-vram, binfo-scrnx, COL8_, 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的状态*/

3、 if (i = 0xfa) mouse_phase = 1; else if (mouse_phase = 1) /*等待鼠标的第一字节*/ mouse_dbuf0 = i; mouse_phase = 2; else if (mouse_phase = 2) /* 等待鼠标的第二字节 */ mouse_dbuf1 = i; mouse_phase = 3; else if (mouse_phase = 3) mouse_dbuf2 = i; mouse_phase = 1; /*鼠标的三个字节都齐了,显示出来*/ sprintf(s, %02X %02X %02X, mouse_dbuf0

4、, mouse_dbuf1, mouse_dbuf2); boxfill8(binfo-vram, binfo-scrnx, COL8_, 32, 16, 32 + 8 * 8 - 1, 31); putfonts8_asc(binfo-vram, binfo-scrnx, 32, 16, COL8_FFFFFF, s); 实际上是将HariMain中for循环部分进行修改,首先把最初读到的0xfa舍弃掉。之后,每次从鼠标那里送过来的数据都应该是3个字节一组的,所以每当数据累积到3个字节,就把他显示在屏幕上。变量mouse_phase用来记住接受鼠标数据的工作进展到了什么阶段(phase)。接

5、受到的数据放在mouse_dbuf02内。 if (mouse_phase = 0) /*等待鼠标的0xfa的状态*/ 各种处理; else if (mouse_phase = 1) /*等待鼠标的第一字节*/ 各种处理; else if (mouse_phase = 2) /* 等待鼠标的第二字节 */ 各种处理; else if (mouse_phase = 3) /*鼠标的三个字节都齐了,显示出来*/ 各种处理; 这部分就是对于不同的mouse_phase值,相应地做各种不同的处理。显示结果如下(鼠标移动过):屏幕上除了括号内的还有三字节数字,即mouse_dbuf0,mouse_dbu

6、f1,mouse_dbuf2里的数据。“08”部分0会在03的范围内变化,这里鼠标左移时显示1,下移时显示2,这是演讲的同学提出的,湛林莉她观察还真是厉害,不仅将上下左右,还把右下、坐下等也看了出来。“8”只有在点击鼠标时才会有变化,值在8F之间。第二个字节与鼠标的左右移动有关,第三个字节与鼠标的上下移动有关。这里的信息方便下面为鼠标的动作做出判断。2. 整理在HariMain函数中出现的unsigned char mouse_dbuf3, mouse_phase;声明可以放到函数前的结构体里:struct MOUSE_DEC unsigned char buf3, phase;123并在这句

7、话修改为:struct MOUSE_DEC mdec;1创建的这个结构体MOUSE_DEC,DEC是decode的缩写,用这个结构日把鼠标所需要的变量都归总到一块儿。 然后将鼠标的解读从函数HariMain的接受信息处理中剥离出来,放到了mouse_decode函数。3. 鼠标解读(2)struct MOUSE_DEC unsigned char buf3, phase; int x, y ,btn;int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) if (mdec-phase = 0) /* 等待鼠标的0xfa的阶段 */

8、 if (dat = 0xfa) mdec-phase = 1; return 0; if (mdec-phase = 1) /* 等待鼠标第一字节的阶段 */ if (dat & 0xc8) = 0x08) /*如果第一字节正确*/ mdec-buf0 = dat; mdec-phase = 2; return 0; if (mdec-phase = 2) /* 等待鼠标第二字节的阶段 */ mdec-buf1 = dat; mdec-phase = 3; return 0; if (mdec-phase = 3) /* 等待鼠标第三字节的阶段 */ mdec-buf2 = dat; mde

9、c-phase = 1; mdec-btn = mdec-buf0 & 0x07; mdec-x = mdec-buf1; mdec-y = mdec-buf2; if (mdec-buf0 & 0x10) != 0) mdec-x |= 0xffffff00; if (mdec-buf0 & 0x20) != 0) mdec-y |= 0xffffff00; mdec-y = - mdec-y; /*鼠标的y方向与画面符号相反*/ return 1; return -1; /* 应该不可能到这里来 */结构体里增加的几个变量用于存放解读结果,这几个变量是x、y和btn,分别用于存放移动信息和

10、鼠标按键状态。if (mdec-phase = 1)这个语句用于判断第一字节对移动有反应的部分是否在03的范围内;同时还要判断第一字节对点击有反应的部分是否在8F的范围内,如果不在以上数据范围内就被舍去。这样做是因为鼠标连线可能会由接触不良,这样产生的数据就有错位,不能顺利解读。if (mdec-phase = 3)语句是解读处理的核心。鼠标键的状态放在buf0的低3位,我们只取出这3位。十六进制的0x07相当于二进制的0000 0111,通过与运算(&)取出低3位。x,y基本上直接使用buf1和buf2,但是需要使用第一字节中对鼠标移动有反应的几位,将x和y的第8位及第8位以后全部都设成1,

11、或全部都保留为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, lcr %4d %4d, mdec.x, mdec.y); if (mdec.btn & 0x01) != 0) s1 = L

12、; if (mdec.btn & 0x02) != 0) s3 = R; if (mdec.btn & 0x04) != 0) s2 = C; boxfill8(binfo-vram, binfo-scrnx, COL8_, 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

13、_get(&mousefifo); io_sti(); if (mouse_decode(&mdec, i) != 0) /*3字节都凑齐了,所以把它们显示出来*/ sprintf(s, lcr %4d %4d, mdec.x, mdec.y); if (mdec.btn & 0x01) != 0) s1 = L; if (mdec.btn & 0x02) != 0) s3 = R; if (mdec.btn & 0x04) != 0) s2 = C; boxfill8(binfo-vram, binfo-scrnx, COL8_, 32, 16, 32 + 15 * 8 - 1, 31);

14、putfonts8_asc(binfo-vram, binfo-scrnx, 32, 16, COL8_FFFFFF, s); /*鼠标指针的移动*/ boxfill8(binfo-vram, binfo-scrnx, COL8_, mx, my, mx + 15 * 8 - 1, my + 15); /*隐藏鼠标*/ mx += mdec.x; my += mdec.y; if (mx x) mx = 0; if (my binfo-scrnx - 16) mx = binfo-scrnx - 16; if (my binfo-scrny - 16) my = binfo-scrny - 1

15、6; sprintf(s, (%sd, %3d), mx, my); boxfill8(binfo-vram, binfo-scrnx, COL8_, 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;m

16、y += mdec.y;是为了防止鼠标指针跑到屏幕外进行的调整。5. 通往32位模式之路这里讲解了asmhead.nas中的程序。; 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 );

17、 /* 禁止从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 waitkbdout这里的waitbdout等同于wait_KBC_sendread,等同于C语言中的:#define KEYCMD_WRITE_OUTPORT 0xd1#define KBC_OUTPORT_A20G_ENABLE 0xdf /* A20G

18、ATE的设定*/ 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。这个附属端口,连接着主板上的很多地方,通过这个端口发送不同的指令,就可以实现各种各

19、样的控制功能。这次输出0xdf所要完成的功能,是让A20GATE信号线变成ON的状态。这条信号线的作用是使内存的1MB以上的部分变成可使用状态。Waite_KBC_sendready();是多余的,在此之后,虽然不会往键盘送命令,但仍然要等到下一个命令能够送来为止。这是为了等待A20GATE的处理切实完成。; 切换到保护模式INSTRSET i486p ; “想要使用486指令”的叙述 LGDT GDTR0 ; 设定临时GDT MOV EAX,CR0 AND EAX,0x7fffffff ; 设bit31为0(为了禁止颁) OR EAX,0x ; 设bit0为1(为了切换到保护模式) MOV

20、CR0,EAX JMP pipelineflushpipelineflush: MOV AX,1*8 ; 可读写的段 32bit MOV DS,AX MOV ES,AX MOV FS,AX MOV GS,AX MOV SS,AXINSTRSET指令,是为了能够使用386以后的LGDT,EAX, CR0等关键字。LGDT指令将暂定的GDT读进来。然后将CR0这一特殊的32寄存器的值带入EAX,并将最高位置为0,最低位置为1,再将这个值返回给CR0寄存器。这样就完成了模式转换,进入到不用颁的保护模式。CR0,也就是control register 0,是一个非常重要的寄存器,只有操作系统才能操作它

21、。保护模式是指操作系统受到CPU的保护,应用程序既不能随便改变段的设定,又不能使用操作系统专用的段。通过带入CR0而切换到保护模式时,要马上执行JMP指令。因为变成保护模式后,机器语言的解释要发生变化。CPU为了加快指令的执行速度而使用了管道(piprline)这一机制。也就是说,前一条指令还在执行的时候就开始解释下一条甚至再下一条指令。因为模式变了,就要重新解释一遍,所以加入了JMP指令。并且在进入保湿模式以后,段寄存器的意思也变了(不再是乘以16后再加算的意思了),除了CS以外所有段寄存器的值都从0x0000变成了0x0008.CS保持原状是因为如果CS也变了,会造成混乱,所以只有CS要放

22、到后面再处理。0x0008,相当于“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 C

23、YLS 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(转送源地址, 转送目的地址, 转送数据的大小

24、); 转送数据大小是以双字节位单位的,所以数据大小用字节数除以4来指定。 memcpy(0x7c00, DSKCAC, 512/4); DSKCAC是0x,所以上面这句话就是从0x7c00复制512字节到0x。这正好是将启动扇区复制到1MB以后的内存去。 memcpy(DSKCAC0+512, DSKCAC+512, cyls*512*18*2/4 - 512/4); 它的意思是将始于0x的磁盘内容,复制到0x那里。上文中“转送数据大小”的计算有点复杂,因为它是以柱面数来计算的,所以需要减去启动区的那一部分长苏。IMUL是乘法运算,SUB是减法运算。bootpack是asmhead,nas的最

25、后一个标签,haribote.hrb连接起来而生成的,所以asmhead结束的地方,紧接着串联着bootpack.hrb最前面的部分。memcpy(bootpack, BOTPAK, 512*1024/4); 从bootpack的地址开始的512KB内容复制到0x号地址去; 必须有asmhead来完成的工作,至此全部完毕; 以后就变由bootpack来完成; bootpack的启动 MOV EBX,BOTPAK MOV ECX,EBX+16 ADD ECX,3 ; ECX += 3; SHR ECX,2 ; ECX /= 4; JZ skip ; 没有要转送的东西时 MOV ESI,EBX+2

26、0 ; 转送源 ADD ESI,EBX MOV EDI,EBX+12 ; 转送目的地 CALL memcpyskip: MOV ESP,EBX+12 ; 栈初始值 JMP DWORD 2*8: 0xb这里仍然是在做memcpy,它对bootpack.hrb的header进行解析,将执行必需的数据传送过去。EBX里带入的是BOTPAK,所以值如下:EBX + 16bootpack.hrb之后的第16号地址。值是0x11a8EBX + 20bootpack.hrb之后的第20号地址。值是0x10c8EBX + 12bootpack.hrb之后的第12号地址。值是0x上面这些值是通过二进制编辑器,打

27、开harib05d的bootpack.hrb后确认的。这些值因harib的版本不同而有所变化。SHA指令是向右移位指令,相当于“ECX=2;”,JZ时条件转移指令,来自英文jump if zero,根据前一个计算结果是否为0来决定是否跳转。最终这个memcpy的作用是将bootpack.hrb第0x10c8字节开始的0x11a8字节复制到0x号地址去。最后将0x代入到ESP里,然后用一个特别的JMP指令,将2*8代入到CS里,同时移动到0x1b号。这里的0x1b号地址是指第2个段的0x1b号地址。第2个段的基地址是0x,所以实际上是从0x28001b开始执行的。也就是bootpack.hrb的

28、0x1b号地址。然后是这个我们制作的这个“纸娃娃系统”的内存分布图:0x - 0x000fffff : 虽然在启动中会多次使用,但之后就变空。(1MB)0x - 0x00267fff : 用于保存软盘的内容。(1440KB)0x - 0x0026f7ff : 空(30KB)0x0026f800 - 0x0026ffff : IDT(64KB)0x - 0x0027ffff : GDT(64KB)0x - 0x002fffff : bootpack.hrb(512KB)0x - 0x003ffff : 栈及其他(1MB)0x - : 空waitkbdout: IN AL,0x64 AND AL,

29、0x02 IN AL,0x60 ; 空读(为了清空数据接收缓冲区中的垃圾数据) JNZ waitkbdout ; AND的结果如果不是0,就跳到waitkbdout RETwaitbdout与wait_KBC_sendready相同,但也添加了部分处理,就是从0x60号设备进行IN的处理。如果控制器里有键盘代码,或者已经积累了鼠标数据,就顺便把它们读取出来。JNC与JZ相反,意思是“jump if not zero”memcpy: MOV EAX,ESI ADD ESI,4 MOV EDI,EAX ADD EDI,4 SUB ECX,1 JNZ memcpy ; 减法运算的结果如果不是0,就跳

30、转到memcpy RET复制内存的程序。ALIGNB 16GDT0:RESB 8 ; NULL selectorDW 0xffff,0x0000,0x9200,0x00cf ; 可以读写的段(segment)32bitDW 0xffff,0x0000,0x9a28,0x0047 ; 可以执行的段(segment)32bit(bootpack用)DW 0GDTR0:DW 8*3-1DD GDT0ALIGNB 16bootpack:ALIGNB指令的意思是一直添加DBO,直到时机合适的时候为止,即最初的地址能被16整除。如果标签GDT0的地址不是8的整数倍,想段寄存器复制的MOV指令就会慢一些。所

31、以插入了ALIGNB指令。GDT0也是一种特定的GDT,0号是空区域(null sector),不能够在那里定义段。1号和2号分别由下式设定:Set_segmdesc(gdt + 1, 0xffffffff, 0x, AR_DATA32_RW);Set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);12GDTR0时LGDT指令,意思是通知GDT0说“有了GDT哟”。在GDT0里,写入了16位的段上限,和32位的段起始地址。最初状态时,GDT在asmhead.nas里,并不在0x0x0027ffff的范围里。IDT连设定都没设

32、定,所以扔处于中断禁止的状态。应当趁着硬件上积累过多数据而产生误动作之前,尽快开放终端,接收数据。因此,在bootpack.c的HariMain里,应该在进行调色板(palette)的初始化以及画面的准备之前,先赶紧重新创建GDT和IDT,初始化PIC,并执行”io_sti();”。二、遇到的问题及解决方法填写说明:分条目列出本次的实验过程中遇到的问题和解决方法(可注明是哪位同学帮忙解决问题),描述问题时应配上相关的截图和标记,描述解决方法时应先分析出现该问题的原因再讲解决方法,尽量详细。1、 鼠标指针“吃掉”任务栏是为啥?因为每次鼠标移动前都要先清除掉目前的鼠标,而作者的做法是让背景色即覆盖

33、指针,所以在上面看起来鼠标移动正常,但移动到任务栏时,任务栏像素显存也被修改为,再加上鼠标本身背景色(bc)也是,所以,鼠标到的地方16*16范围内背景也会变为.2、 Ipl.bin,asmhead.bin,bootpack.hrb三个文件在软盘中的储存地址。打开软盘文件和asmhead.bin文件可以看出lpl.bin地址为000-1ff, asmhead.bin地址为0x4200-0x432f,又因为bootpack紧接在asmhead.bin后,则其地址为0x4330-0x6b833、 2中文件加载在内存的初始地址和复制后地址。启动区lpl地址应为0x7c00-0x7dff, asmhe

34、ad.bin地址应为0xc200-c32f, bootpack.hrb加载在内存地址为:0xc330-0xeb83复制后的地址分别为:0x-0xff, asmhead.bin地址应为0x-0xf, bootpack.hrb复制后应该有两个?我看是复制了两次(没看到诶),一个应该在asmhead.bin后,地址为0x-0x00106b83.另外开辟了一个512kb的内存,地址为0x-0x002fffff;三、程序设计创新点1.实现鼠标移动的同时不会“吃掉”背景;具体实现步骤:A,开辟一个大小为256的整形数组,用来保存鼠标下一次显示位置的显存信息;B,给数组初始化为当前鼠标该有背景色,这里为,2

35、56个像素全部初始化;C,恢复当前鼠标位置背景,即将数组数据赋给当前鼠标像素;D,将下一次鼠标显示位置的显存信息保存在数组里,覆盖原来的值。(这里在mx,my改变后,鼠标显示前进行,就可以利用mx,my取到相关信息);E,显示鼠标下一步的位置(这里稍作修改,只显示光标,背景bc不显示,就好办多了);F,重复步骤C,D,E。效果图如下:关键代码:2.实现菜单的点击显示与隐藏。A,显示。用许多boxfill函数做成菜单底部,再用putfonts8_asc显示字符。B,鼠标有效点击范围。作者写了点击改变字符的操作可以帮到忙,就在里面写判断语句判断鼠标位置,符合即取反flag,flag=1时显示菜单,不等就隐藏菜单。C,主菜单和从菜单的解决,主从菜单有各自的标志位,主标志位为

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 教案示例

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁