《30天自制操作系统》07_day_学习笔记
harib04a:
P126 获取按键编码;
让程序在按下键盘的键之后,将键值编码显示出来
修改的是前面编写的鼠标按键的处理键盘中断的函数inthandler21()
这里笔者介绍了怎样把中断号告诉CPU:
1、计算0x60+IRQ号码
2、把结果输出给OCW2寄存器
3、具体方法:调用io_out8(PIC0_OCW2, 0x60+IRQ);
//int.c节选,修改键盘中断处理函数
void inthandler21(int *esp)
{
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
unsigned char data, s[];
io_out8(PIC0_OCW2, 0x61); /* 通知PIC已经发生了IRQ1中断 */
data = io_in8(PORT_KEYDAT); //获取键盘的按键键值,放到DATA中
sprintf(s, "%02X", data); //data写到S中;
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, , , , );
putfonts8_asc(binfo->vram, binfo->scrnx, , , COL8_FFFFFF, s);
return;
}
harib04b:
加快中断处理,上一步获取键盘键值的中断写在了中断处理程序中
这样如果这时有其他的中断来了就佷尴尬了
加速原理:利用缓冲区(笔者使用了一个变量)把读到的键值先保存在缓冲区中,需要时,再由HarMain去查看
注 意:键盘中有的键是一个字节,有的键是两个字节;
//加快中断处理第一步:增加键值缓冲区
struct KEYBUF keybuf{ //键值缓冲区结构体,data:数据位,flag:标志位
unsigned char data,flag;
};
void inthandler21(int *esp) {
unsigned char data;
io_out8(PIC0_OCW2, 0x61); /* 通知PIC已经发生了IRQ1中断 */
data = io_in8(PORT_KEYDAT); //获取键值
if (keybuf.flag == ) { //标志位为0表示缓冲区空,可以放键值
keybuf.data = data;
keybuf.flag = ;
}
return;
}
//加快中断处理第二步:修改io_halt的无限循环
for (;;) {
io_cli(); //io_cli指令屏蔽中断,因为在后面的处理,防止后面的处理中有中断进来,发生不可预料的结果
if (keybuf.flag == ) {
io_stihlt(); //缓冲区空闲,执行STI和HLT指令;这时,PIC准备好接受中断唤醒CPU
} else { //缓冲区不空闲,将获取的键值输出来,接着标志位置零。
i = keybuf.data;
keybuf.flag = ;
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, , , , );
putfonts8_asc(binfo->vram, binfo->scrnx, , , COL8_FFFFFF, s);
}
}
harib04c:
P131 制作FIFO缓冲区;
思 考:为什么按下和松开都有键值,CTRL键又不一样;
原 因:我们设定的缓冲区struct KEYBUF keybuf{ unsigned char data,flag};只有一个字节
下面笔者加大了缓冲区的长度,并用FIFO的栈机制:
struct KEYBUF keybuf{
unsigned char data[]; //缓冲区大小增加为32个字节
int next; //指向缓冲区的下一个,因为是字符型数组
};
//缓冲区数据的程序用FIFO机制做了相应的调整
for (;;) {
io_cli(); //io_cli指令屏蔽中断,
if (keybuf.next == ) {
io_stihlt(); //缓冲区空闲,执行STI和HLT指令;
} else {
i = keybuf.data[];
keybuf.next--; //不断的从缓冲区读和写FIFO
for (j = ; j < keybuf.next; j++) {
keybuf.data[j] = keybuf.data[j + ];
}
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, , , , );
putfonts8_asc(binfo->vram, binfo->scrnx, , , COL8_FFFFFF, s);
}
}
harib04d:(这一部分请对照图片看!)
到这里位置数据移送最多只能有32个字节(明显不够)
到上面为止,数据移送都是在禁止中断的情况下:
1、在FOR循环中首先进行的就是中断屏蔽: io_cli();//io_cli指令屏蔽中断;
2、之后才能进行键盘的数据接收;
思 考:如果每次读数据都要先屏蔽中断,这样也太。。。。(麻烦)。。怎么办?
解 决:笔者接下来开发了一个不需要数据移送操作的FIFO缓冲区;大致运用了循环链表的思想:
如上图所示:当写入的位置到达缓冲区末尾,缓冲区开头应该已经开始变空(如果没有变空,说明数据读跟不上数据写,那么只好把部分数据扔掉)。因此,如果下一个数据写入位置到了32以后,就强制性的将其置0;对下一个数据读出位置也做同样的处理,一旦到了32以后,就把它设置从0开始据徐读取数据。这样32字节的缓冲区就能一圈一圈的不断循环(其实就是循环链表;如果看不懂我的解释,请看书本P134内容)
//next_r :下一个读的位置
//next_w :下一个写的位置
// len :缓冲区能记录多少字节的数据
struct KEYBUF {
unsigned char data[];
int next_r, next_w, len; };
接下来做的事:修改中断处理程序(void inthandler21(int *esp))和io_halt的无限循环;下面是io_halt修改的部分:
for (;;) {
io_cli();
if (keybuf.len == ) {
io_stihlt(); //这样每一次屏蔽中断的时间有1/2降低为1/32
} else {
i = keybuf.data[keybuf.next_r];
keybuf.len--;
keybuf.next_r++;
if (keybuf.next_r == ) {
keybuf.next_r = ;
}
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, , , , );
putfonts8_asc(binfo->vram, binfo->scrnx, , , COL8_FFFFFF, s);
}
}
harib04e:
我们知道,每次鼠标产生动作,会连续发送3个字节的数据(两个坐标和一个状态信息)
接下来我们进一步修改缓冲区的内容,让他也能适应我们要做的鼠标的移动(重新定义缓冲区):
//1、缓冲区大小改为可变,不再是32字节了
//2、保存缓冲区的总字节数size
//3、缓冲区空闲的字节数free
//4、缓冲区的地址buf
struct FIFO8 {
unsigned char *buf;
int p, q, size, free, flags;
};
作者其实是相当负责的,接着作者写了几个相关的操作函数以便于后续的调用;这些函数都被封装在FIFO.C中(FIFO.C代码较长,我们折叠起来吧!):
/* FIFO.c */
#include "bootpack.h"
#define FLAGS_OVERRUN 0x0001 void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf)
/* FIFO缓冲区的初始化,用来设定FIFO8的结构地址以及有关的各种参数 */
{
fifo->size = size;
fifo->buf = buf;
fifo->free = size; /* 缓冲区大小 */
fifo->flags = ;
fifo->p = ; /* 下一个数据写入的位置 */
fifo->q = ; /* 下一个读数据的位置 */
return;
} int fifo8_put(struct FIFO8 *fifo, unsigned char data)
/* 向FIFO缓冲区存储一个字节的数据 */
{
if (fifo->free == ) { /* 溢出了 */
fifo->flags |= FLAGS_OVERRUN;
return -; //返回-1 溢出了
}
fifo->buf[fifo->p] = data;
fifo->p++;
if (fifo->p == fifo->size) {
fifo->p = ;
}
fifo->free--;
return ; //返回0,没有溢出
} int fifo8_get(struct FIFO8 *fifo)
/* 从缓冲区取一个字节的函数 */
{
int data;
if (fifo->free == fifo->size) {
/* 如果缓冲区为空返回-1 */
return -;
}
data = fifo->buf[fifo->q];
fifo->q++;
if (fifo->q == fifo->size) {
fifo->q = ;
}
fifo->free++;
return data;
}
int fifo8_status(struct FIFO8 *fifo)
/* 调出缓冲区的状态,报告到底积攒了多少数据 */
{
return fifo->size - fifo->free;
}
FIFO.C
接下来做的事,和上面相同:修改中断处理程序(void inthandler21(int *esp));和io_halt的无限循环;
void inthandler21(int *esp) //修改中断处理程序(void inthandler21(int *esp))
{
unsigned char data;
io_out8(PIC0_OCW2, 0x61); /* PIC打开IRQ-1中断口,告诉CPU */
data = io_in8(PORT_KEYDAT);
fifo8_put(&keyfifo, data); //看见木有,直接调用封装在fifo.c中的函数
return;
}
for (;;) { //MariMain中也做相应调整;io_halt的循环早就没有啦
io_cli();
if (fifo8_status(&keyfifo) == ) {
io_stihlt();
} else {
i = fifo8_get(&keyfifo);
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, , , , );
putfonts8_asc(binfo->vram, binfo->scrnx, , , COL8_FFFFFF, s);
}
}
harib04f:
好了,现在我们又要开始折腾鼠标了!
还记得前面笔者给鼠标和键盘分配的PIC的中断号是多少吗?(键盘:IRQ01;鼠标:IRQ12)
笔者在书中这一部分首先给我们普及了一下鼠标是如何兴起的。接着普及了鼠标一些操作的一些变化(一句话:以前的鼠标操作和现在不同)
我们先来看看控制电路是什么情况:
注 意:鼠标控制器和键盘控制器实际上集成在同一个控制电路中。
void wait_KBC_sendready(void)
{ /* 等待键盘控制电路准备完成 */
//如果键盘端口就绪PROT_KEYSTA & 处于准备发送数据的状态KEYSTA_SEND_NOTREADY
//表示键盘控制电路已经准备完毕了。跳出去,返回,不再等待
for (;;) { if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == ) { break; } }
return;
}
void init_keyboard(void) { /* 初始化键盘 */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, KBC_MODE);
return;
}
接下来向控制器发送指令,激活鼠标:
//激活鼠标的相关程序,
//这里和上一部中的void init_keyboard(void)初始化键盘很相似,发现了没有?
//没错,就是因为这两个设备的控制器实际上是在同一个控制电路中的
#define KEYCMD_SENDTO_MOUSE 0xd4 //键盘的使能信号
#define MOUSECMD_ENABLE 0xf4 //鼠标的使能信号
void enable_mouse(void) //鼠标使能函数,想控制器发送激活指令
{ /* 激活鼠标, */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
return; /* 激活成功,返回ACK(0xfa) */
}
harib04g:
P142 从鼠标接收数据;原理和上面的从键盘接受数据相同
在 harib04e 中,我们已经修改好了缓冲区,让他同时成为鼠标和键盘数据的缓冲(详见harib04e)
那么我们要做什么事呢?
没错,和键盘接受数据一样,修改两个东西:鼠标的中断程序(函数):inthandler2c() 和 io_halt的无限循环
理解了上面键盘的做法,到这里理解起来就很简单了;直接上代码:
//怎么样。鼠标的中断程序和键盘中断程序inthandler21(int *esp)神似,有木有?
void inthandler2c(int *esp) /* PS/2的鼠标中断 */
{
unsigned char data;
io_out8(PIC1_OCW2, 0x64); /* IRQ-12已经受理完成 */
io_out8(PIC0_OCW2, 0x62); /* IRQ-02已经受理完成 */
data = io_in8(PORT_KEYDAT);
fifo8_put(&mousefifo, data);
return;
}
//取数据程序(io_halt的无限循环)
//这里和键盘的取数据程序也神似,不同的是,缓冲区开到了128字节;
//因为鼠标的数据量更大
fifo8_init(&mousefifo, , mousebuf){
if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == ) {
io_stihlt();
} else {
if (fifo8_status(&keyfifo) != ) {
i = fifo8_get(&keyfifo);
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, , , , );
putfonts8_asc(binfo->vram, binfo->scrnx, , , COL8_FFFFFF, s);
} else if (fifo8_status(&mousefifo) != ) {
i = fifo8_get(&mousefifo);
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, , , , );
putfonts8_asc(binfo->vram, binfo->scrnx, , , COL8_FFFFFF, s);
}
}
《30天自制操作系统》07_day_学习笔记的更多相关文章
- 《30天自制操作系统》学习笔记--Mac下工具的使用
现在来介绍官网上下的工具怎么用首先是官网地址,书上有个注释上有:hrb.osask.jp 翻译成中文大概是这个样子滴. 上面有两个文件可以下载,一个是工具,一个是工具的源代码,很好的学习资料 下面把工 ...
- 《30天自制操作系统》学习笔记--Mac环境搭建
弄了三天了,终于弄好了,先说结果,就是作者在网站上放了os x的工具(hrb.osask.jp,也有linux下的工具,可以自己去下载),也就是说我白忙活了三天... 再说一下这几天都干啥了,主要是想 ...
- 《30天自制操作系统》学习笔记--番外篇之Mac环境下的工具介绍
这几天又有点不务正业了,书也没看,一直在搞这个破环境,尝试各种做法,网上各种垃圾信息,浪费了很多时间,说的基本都是废话,不过还是找到了一些,赶紧写下来,不然这个过几天又忘了 首先是环境,我用的是Max ...
- 《30天自制操作系统》读书笔记(5) GDT&IDT
梳理项目结构 项目做到现在, 前头的好多东西都忘了, 还是通过Makefile重新理解一下整个项目是如何编译的: 现在我们拥有这么9个文件: ipl10.nas InitialProgramLo ...
- 《30天自制操作系统》读书笔记(3) 引入C语言
这一次的学习相当曲折, 主要是因为粗心, Makefile里面的错误导致了文件生成出现各种奇奇怪怪的问题, 弄得心力交瘁, 因此制作过程还是尽量按着作者的路子来吧. 作者提供的源码的注释在中文系统下是 ...
- 《30天自制操作系统》读书笔记(2)hello, world
让系统跑起来 要写一个操作系统,我们首先要有一个储存系统的介质,原版书似乎是06年出版的,可惜那时候没有电脑,没想到作者用的还是软盘,现在的电脑谁有软驱?不得已我使用一张128M的SD卡来代替,而事实 ...
- 30天自制操作系统第九天学习笔记(u盘软盘双启动版本)
暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078 ,更多学习中的问题.资料,群里分享 environment:开发环境:ubuntu 第九天的课程已学完,确实有点不想写 ...
- 从你的u盘启动:30天自制操作系统第四天u盘启动学习笔记
暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078 ,更多学习中的问题.资料,群里分享 developing environment:ubuntu 关于u盘启动自己做的操 ...
- 30天自制操作系统第八天学习笔记(u盘软盘双启动版本)
暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078 ,更多学习中的问题.资料,群里分享 environment:开发环境:ubuntu 第八天的学习思考: 关于鼠标是怎么 ...
- 《30天自制操作系统》笔记(03)——使用Vmware
<30天自制操作系统>笔记(03)——使用Vmware 进度回顾 在上一篇,实现了用IPL加载OS程序到内存,然后JMP到OS程序这一功能:并且总结出下一步的OS开发结构.但是遇到了真机测 ...
随机推荐
- bug 发表文章不显示图片
bug 描述: 现象是我们这不能发布图片, 测试说患教方向是可以正常发布图片的(还是要感激测试,正是他们鞭策我们不断挑战困难,解决之,从而提高自己姿势水平). 图片没上传上去, 服务端协助查找发现没调 ...
- Natural Language Toolkit
http://www.nltk.org/ >>> import nltk >>> nltk.download()
- jboss4.2.3 SSL配置 + 生成数字签名
一.生成数字签名 1. 生成JKS文件 keytool -genkey -keyalg RSA -alias jbosskey -keystore jbosskey.jks 在win7系统中,该文件的 ...
- postgre去重复记录
postgre去重复记录,主要用到row定位的一个系统表示 “ctid”,能查出纯净的不重复的记录,那要删掉重复值也就容易了,自己去折腾吧. 我所涉及的是得到不重复的记录,就一句话: select c ...
- (转)CAS (4) —— CAS浏览器SSO访问顺序图详解(CAS Web Flow Diagram by Example)
CAS (4) —— CAS浏览器SSO访问顺序图详解(CAS Web Flow Diagram by Example) tomcat版本: tomcat-8.0.29 jdk版本: jdk1.8.0 ...
- php YAF
Yaf 的特点: 用C语言开发的PHP框架, 相比原生的PHP, 几乎不会带来额外的性能开销. 所有的框架类, 不需要编译, 在PHP启动的时候加载, 并常驻内存. 更短的内存周转周期, 提高内存利用 ...
- c# ToString() 用法
string tempa = Convert.ToString(31, 2);//将10进制数31转换为2进制字符串. string strNums = int.Parse(tempa).ToStri ...
- 小易邀请你玩一个数字游戏,小易给你一系列的整数。你们俩使用这些整数玩游戏。每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字。 例如: 如果{2,1,2,7}是你有的一系列数,小易说的数字是11.你可以得到方案2+2+7 = 11.如果顽皮的小易想坑你,他说的数字是6,那么你没有办法拼凑出和为6 现在小易给你n个数,让你找出无法从n个数中选取部分求和
小易邀请你玩一个数字游戏,小易给你一系列的整数.你们俩使用这些整数玩游戏.每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字. 例如: 如果{2,1,2 ...
- PowerDesigner生成SQL Server 2008脚本注释乱码的问题
[%OWNER%?[.O:[execute ][exec ]]sp_addextendedproperty [%R%?[N]]'MS_Description', N[%R%?[N]]%.q:COMME ...
- 使用Dom的Range对象处理chrome和IE文本光标位置
有这样一段js: var sel = obj.createTextRange(); sel.move('character', num); sel.collapse(); sel.select(); ...