![]() |
#2
chengstone2010-06-14 09:08
|
我将所有的代码以及对应的img文件一起打包在了下面的压缩文件里。
因为是使用yc09编译器在xp下编译的,所以若想要修改代码的话,需要安装yc09编译器。修改代码后,无需手动编译整个工程,只需要运行压缩包里的run.exe文件(要先将整个压缩包解压)即可自动编译整个工程并且将img加载到虚拟机中,启动操作系统。当然也可以直接使用虚拟机加载img,运行看看这个操作系统(需要安装bochs虚拟机,然后双击debug.bxrc文件)
只有本站会员才能查看附件,请 登录
下面对此一步对操作系统的改动和新添加内容作简要介绍。
对域结构的扩展:
先看看域结构最核心的两个数据结构:on事件(被动动作)和动作(主动动作)。

//on事件结构
struct on_s
{
char name[NAME_MAX]; //on事件名称
on_fun run; //on调用的函数
struct on_s *next; //下一个on事件
char state; //保留,暂时没有特别用处
};
struct on_s
{
char name[NAME_MAX]; //on事件名称
on_fun run; //on调用的函数
struct on_s *next; //下一个on事件
char state; //保留,暂时没有特别用处
};

//动作结构
struct action_s
{
char name[NAME_MAX]; //动作名称
action_fun run; //动作调用的函数
struct action_s *last; //上一动作
struct action_s *next; //下一动作
struct on_s *before; //执行动作前,会调用的on事件(链表)
struct on_s *after; //执行动作后,会调用的on事件(链表)
};
struct action_s
{
char name[NAME_MAX]; //动作名称
action_fun run; //动作调用的函数
struct action_s *last; //上一动作
struct action_s *next; //下一动作
struct on_s *before; //执行动作前,会调用的on事件(链表)
struct on_s *after; //执行动作后,会调用的on事件(链表)
};
对于on事件结构,没有任何改改变,但是下面将会看到,在实现键盘功能键时,将struct on_s *next; 字段利用上了
对于动作结构,新添加了两个on事件指针,分别用于在执行动作前后执行。
下面是根据新添加的中断,修改后的run()函数,主要是分别在执行动作函数先后执行(加载)了on事件,以及在执行on事件后,将on事件后链接的on事件加载到队列中,在下一个动作周期会被调用执行。

void Run()
{
static int on_idx;
static struct on_s *pOn;
//处理当前动作
if(actionList.seek != NULL)
{
//先执行动作执行前的On事件(只执行第一个)
pOn = (*actionList.seek).before;
if(pOn != NULL)
{
(*actionList.seek).before = NULL;
(*pOn).run();
//若这个On事件后链接了其他On事件,就加载到队列中,执行完动作后执行
if((*pOn).next != NULL)
AddOn((*pOn).next);
}
(*actionList.seek).run();//执行当前动作
//执行动作执行后的On链表上的On事件
pOn = (*actionList.seek).after;
if(pOn != NULL)
{
(*actionList.seek).after = NULL;
AddOn(pOn);
}
}
//处理on事件的控制结构
on_idx = on_list.idx;
asm{cli}
on_list.flag = -on_list.flag;//改变堆栈增长方向
on_list.total =((on_list.flag == 1)?(ON_LIST_MAX - on_list.idx -1):on_list.idx);
on_list.idx=(on_list.flag == 1) ? 0 : ON_LIST_MAX -1;
asm{sti}
//一次性的执行on堆栈中的on事件
for(int i = ((on_list.flag == 1)?(ON_LIST_MAX -1):0); i != on_idx; i-=on_list.flag)
{
(*on_list.list[i]).run();
//若这个On事件后链接了其他On事件,就加载到队列中,下一个动作周期执行
if((*on_list.list[i]).next != NULL)
AddOn((*on_list.list[i]).next);
}
//指向下一个动作
if(actionList.seek != NULL)
actionList.seek = (*actionList.seek).next;
}
此外,就是四个与之配套使用的函数。{
static int on_idx;
static struct on_s *pOn;
//处理当前动作
if(actionList.seek != NULL)
{
//先执行动作执行前的On事件(只执行第一个)
pOn = (*actionList.seek).before;
if(pOn != NULL)
{
(*actionList.seek).before = NULL;
(*pOn).run();
//若这个On事件后链接了其他On事件,就加载到队列中,执行完动作后执行
if((*pOn).next != NULL)
AddOn((*pOn).next);
}
(*actionList.seek).run();//执行当前动作
//执行动作执行后的On链表上的On事件
pOn = (*actionList.seek).after;
if(pOn != NULL)
{
(*actionList.seek).after = NULL;
AddOn(pOn);
}
}
//处理on事件的控制结构
on_idx = on_list.idx;
asm{cli}
on_list.flag = -on_list.flag;//改变堆栈增长方向
on_list.total =((on_list.flag == 1)?(ON_LIST_MAX - on_list.idx -1):on_list.idx);
on_list.idx=(on_list.flag == 1) ? 0 : ON_LIST_MAX -1;
asm{sti}
//一次性的执行on堆栈中的on事件
for(int i = ((on_list.flag == 1)?(ON_LIST_MAX -1):0); i != on_idx; i-=on_list.flag)
{
(*on_list.list[i]).run();
//若这个On事件后链接了其他On事件,就加载到队列中,下一个动作周期执行
if((*on_list.list[i]).next != NULL)
AddOn((*on_list.list[i]).next);
}
//指向下一个动作
if(actionList.seek != NULL)
actionList.seek = (*actionList.seek).next;
}

//将一个On事件链表添加到某个On事件链表的最后
void AddToOnList(struct on_s *headOn,struct on_s *newOn)
{
...
}
//将某个On事件从一个On事件链表移除(不考虑要移除的On事件为链头)
void DelFromOnList(struct on_s *headOn,struct on_s *delOn)
{
...}
//将一个On事件添加动作函数的before On(执行动作前执行的On事件)链表
void AddToActionHead(struct action_s *theAction,struct on_s *newOn)
{
...
}
//将一个On事件添加动作函数的after On(执行动作前执行的On事件)链表
void AddToActionTail(struct action_s *theAction,struct on_s *newOn)
{
...
}
void AddToOnList(struct on_s *headOn,struct on_s *newOn)
{
...
}
//将某个On事件从一个On事件链表移除(不考虑要移除的On事件为链头)
void DelFromOnList(struct on_s *headOn,struct on_s *delOn)
{
...}
//将一个On事件添加动作函数的before On(执行动作前执行的On事件)链表
void AddToActionHead(struct action_s *theAction,struct on_s *newOn)
{
...
}
//将一个On事件添加动作函数的after On(执行动作前执行的On事件)链表
void AddToActionTail(struct action_s *theAction,struct on_s *newOn)
{
...
}
对键盘模块的扩展:
最明显的,就是增加了一堆的on事件,这些on事件对应的注册到键盘扫描码上,像shift、ctrl等,用于配合字符部分的输入,其他的功能键,则是提供给视频作为控制事件的注册点。此外,就是对键盘的扫描码转字符的模块做了细微调整,以便于更好的处理小键盘部分的按键。详细的情况,就仔细看看keyboard.h和keyboard.c两个文件吧。

//处理和字符结合的键盘事件void OnShiftDownFun();
struct on_s onShiftDown = {"onShiftDown",&OnShiftDownFun,NULL,NULL};
void OnShiftUpFun();
struct on_s onShiftUp = {"onShiftUp",&OnShiftUpFun,NULL,NULL};
void OnCapsLockUpFun();
struct on_s onCapsLockUp = {"onCapsLockUp",&OnCapsLockUpFun,NULL,NULL};
void OnNumLockUpFun();
struct on_s onNumLockUp = {"onNumLockUp",&OnNumLockUpFun,NULL,NULL};
//处理ctrl按下的键盘事件
void OnCtrlDownFun();
struct on_s onCtrlDown = {"onCtrlDown",&OnCtrlDownFun,NULL,NULL};
void OnCtrlUpFun();
struct on_s onCtrlUp = {"onCtrlUp",&OnCtrlUpFun,NULL,NULL};
...
...
struct on_s onShiftDown = {"onShiftDown",&OnShiftDownFun,NULL,NULL};
void OnShiftUpFun();
struct on_s onShiftUp = {"onShiftUp",&OnShiftUpFun,NULL,NULL};
void OnCapsLockUpFun();
struct on_s onCapsLockUp = {"onCapsLockUp",&OnCapsLockUpFun,NULL,NULL};
void OnNumLockUpFun();
struct on_s onNumLockUp = {"onNumLockUp",&OnNumLockUpFun,NULL,NULL};
//处理ctrl按下的键盘事件
void OnCtrlDownFun();
struct on_s onCtrlDown = {"onCtrlDown",&OnCtrlDownFun,NULL,NULL};
void OnCtrlUpFun();
struct on_s onCtrlUp = {"onCtrlUp",&OnCtrlUpFun,NULL,NULL};
...
...
对视频模块的扩展:
对于视频模块,可以分成三部分:对显存起始位置的设置以及对光标的设置相关的函数,将这些设置转换为键盘控制的一堆on事件,对向显存写入字符串的字符输出动作模块。

//对屏幕的一些操作函数
void ResetVideoStartAddr();//根据videoStartAddr设置显存显示起始位置
void ChangVideoStartAddr(int addr);//根据当前显示起始位置进行偏移:videoStartAddr+=addr
asm void ClearScreen();//清屏函数(使用字符' ',蓝底红字擦除一遍所有的页)
void SetVideoColor(int x,int y,char color);//修改当前屏幕指定坐标的前景背景色
void set_cursor(unsigned int position);//设置光标位置
void set_video_start_addr(t_32 addr);//设置显存起始位置:videoStartAddr=addr
//void OutChar();//向显存写入一个字符
void ResetVideoStartAddr();//根据videoStartAddr设置显存显示起始位置
void ChangVideoStartAddr(int addr);//根据当前显示起始位置进行偏移:videoStartAddr+=addr
asm void ClearScreen();//清屏函数(使用字符' ',蓝底红字擦除一遍所有的页)
void SetVideoColor(int x,int y,char color);//修改当前屏幕指定坐标的前景背景色
void set_cursor(unsigned int position);//设置光标位置
void set_video_start_addr(t_32 addr);//设置显存起始位置:videoStartAddr=addr
//void OutChar();//向显存写入一个字符

void OnVideoPageUpFun();//向上滚动一页
struct on_s onVideoPageUp = {"onVideoPageUp",&OnVideoPageUpFun,NULL};
void OnVideoPageDownFun();//向下滚动一页
struct on_s onVideoPageDown = {"onPageDownDown",&OnVideoPageDownFun,NULL};
void OnVideoLineUpFun();//向上滚动一行
struct on_s onVideoLineUp = {"onVideoLineUp",&OnVideoLineUpFun,NULL};
void OnVideoLineDownFun();//向下滚动一行
struct on_s onVideoLineDown = {"onVideoLineDown",&OnVideoLineDownFun,NULL};
...
...
struct on_s onVideoPageUp = {"onVideoPageUp",&OnVideoPageUpFun,NULL};
void OnVideoPageDownFun();//向下滚动一页
struct on_s onVideoPageDown = {"onPageDownDown",&OnVideoPageDownFun,NULL};
void OnVideoLineUpFun();//向上滚动一行
struct on_s onVideoLineUp = {"onVideoLineUp",&OnVideoLineUpFun,NULL};
void OnVideoLineDownFun();//向下滚动一行
struct on_s onVideoLineDown = {"onVideoLineDown",&OnVideoLineDownFun,NULL};
...
...

#define STRING_BUF_MAX 8 //字符输入缓冲区大小
struct stringBuf_s
{
int idx; //缓冲区中共有多少字节
char *buf[STRING_BUF_MAX]; //缓冲区
}stringBuf;
int print_life = 0;
void PrintActionFun();//输出动作,用于管理控制台的输出任务
struct action_s printAction = {"printAction",&PrintActionFun,NULL,NULL,NULL,NULL};
struct stringBuf_s
{
int idx; //缓冲区中共有多少字节
char *buf[STRING_BUF_MAX]; //缓冲区
}stringBuf;
int print_life = 0;
void PrintActionFun();//输出动作,用于管理控制台的输出任务
struct action_s printAction = {"printAction",&PrintActionFun,NULL,NULL,NULL,NULL};
将对显存的操作操作的on事件映射到对应的键盘功能键按钮是通过下面这个函数实现的:

//初始化控制台,向键盘按钮注册一些on事件来操纵视频
void InitConsole()
{
AddToOnList(onF1Up,onVideoPage1);
AddToOnList(onF2Up,onVideoPage2);
AddToOnList(onF3Up,onVideoPage3);
AddToOnList(onF4Up,onVideoPage4);
AddToOnList(onF5Up,onVideoPage5);
AddToOnList(onF6Up,onVideoPage6);
AddToOnList(onF7Up,onVideoPage7);
AddToOnList(onF8Up,onVideoPage8);
AddToOnList(onHomeDown,onVideoPage1);
AddToOnList(onEndDown,onVideoPage8);
AddToOnList(onArrowDownDown,onVideoLineDown);
AddToOnList(onArrowUpDown,onVideoLineUp);
AddToOnList(onPageDownDown,onVideoPageDown);
AddToOnList(onPageUpDown,onVideoPageUp);
}
void InitConsole()
{
AddToOnList(onF1Up,onVideoPage1);
AddToOnList(onF2Up,onVideoPage2);
AddToOnList(onF3Up,onVideoPage3);
AddToOnList(onF4Up,onVideoPage4);
AddToOnList(onF5Up,onVideoPage5);
AddToOnList(onF6Up,onVideoPage6);
AddToOnList(onF7Up,onVideoPage7);
AddToOnList(onF8Up,onVideoPage8);
AddToOnList(onHomeDown,onVideoPage1);
AddToOnList(onEndDown,onVideoPage8);
AddToOnList(onArrowDownDown,onVideoLineDown);
AddToOnList(onArrowUpDown,onVideoLineUp);
AddToOnList(onPageDownDown,onVideoPageDown);
AddToOnList(onPageUpDown,onVideoPageUp);
}
具体的实现代码都很简单,参考console.h和console.c两个文件的代码即可明白。
最后要说明的是,我将显存分为连续的八个页,使用F1~F8可以直接跳转到对应的页,也可以使用PageUp、PageDown、Home、End等按钮,此外,我特地添加了显示当前页位置小滑块,运行img即可看到效果。