模拟分页式存储管理中硬件的地址转换和产生缺页中断
一、实验目的
在计算机系统中,为了提高主存利用率,往往把辅助存储器(如
磁盘)作为主存储器的扩充,使多道运行的作业的全部逻辑地址空间
总和可以超出主存的绝对地址空间。用这种办法扩充的主存储器称为
虚拟存储器。通过本实验帮助同学理解在分页式存储管理中怎样实现
虚拟存储器。
二、实验要求及实验环境
第一题:模拟分页式存储管理中硬件的地址转换和产生缺页中
断。分页式虚拟存储系统是把作业信息的副本存放在磁盘上,当作业
被选中时,可把作业的开始几页先装入主存且启动执行。为此,在为
作业建立页表时,应说明哪些页已在主存,哪些页尚未装入主存。
作业执行时,指令中的逻辑地址指出了参加运算的操作存放的页
号和单元号,硬件的地址转换机构按页号查页表,若该页对应标志为
“1”,则表示该页已在主存,这时根据关系式“绝对地址=块号×块
长+单元号”计算出欲访问的主存单元地址。如果块长为 2 的幂次,
则可把块号作为高地址部分,把单元号作为低地址部分,两者拼接而
成绝对地址。若访问的页对应标志为“0”,则表示该页不在主存,这
时硬件发“缺页中断”信号,有操作系统按该页在磁盘上的位置,把
该页信息从磁盘读出装入主存后再重新执行这条指令。设计一个“地
址转换”程序来模拟硬件的地址转换工作。当访问的页在主存时,则
形成绝对地址,但不去模拟指令的执行,而用输出转换后的地址来代
替一条指令的执行。当访问的页不在主存时,则输出“* 该页页号”,
表示产生了一次缺页中断。
第二题:用先进先出(FIFO)页面调度算法处理缺页中断。
在分页式虚拟存储系统中,当硬件发出“缺页中断”后,引出操
作系统来处理这个中断事件。如果主存中已经没有空闲块,则可用
FIFO 页面调度算法把该作业中最先进入主存的一页调出,存放到磁
盘上,然后再把当前要访问的页装入该块。调出和装入后都要修改页
表页表中对应页的标志。
FIFO 页面调度算法总是淘汰该作业中最先进入主存的那一页,
因此可以用一个数组来表示该作业已在主存的页面。假定作业被选中
时,把开始的 m 个页面装入主存,则数组的元素可定为 m 个。
编制一个 FIFO 页面调度程序,为了提高系统效率,如果应淘汰
的页在执行中没有修改过,则可不必把该页调出(因在磁盘上已有副
本)而直接装入一个新页将其覆盖。由于是模拟调度算法,所以,不
实际启动输出一页和装入一页的程序,而用输出调出的页号和装入的
页号来代替一次调出和装入的过程。
三、设计思想(本程序中的用到的所有数据类型的定义,主
程序的流程图及各程序模块之间的调用关系)
1.程序流程图
以下为 FIFO 算法流程:
2 .逻辑设计
使用线性表保存页表。每个节点信息包括调入主存的标志,主
存块号,在磁盘上的位置,修改标志等。使用线性表保存 FIFO 算法
使用的对应关系数组 P,用数组模拟实现调度的队列。该队列需支持
查找,插入和删除操作(即替换操作)。
3、物理设计
全局定义如下:
struct info//页表
{
bool flag; //标志
long block;//块号
long disk;//在磁盘上的位置
bool dirty;//修改标志
}pagelist[SizeOfPage];
long po;//队列标记
long P[M];
使用函数 init()进行初始化,使用循环结构读入各条指令。
四、测试结果
实际运行的结果如下:
请选择题号(1/2):1
请输入指令的页号和单元号:
0 70
绝对地址=710
请输入指令的页号和单元号:
4 053
* 4
请输入指令的页号和单元号:
1 50
绝对地址=1074
请输入指令的页号和单元号:
5 023
* 5
请输入指令的页号和单元号:
2 15
绝对地址=1167
请输入指令的页号和单元号:
1 037
绝对地址=1061
请输入指令的页号和单元号:
exit
请选择题号(1/2):2
请输入指令的页号、单元号,以及是否为存指令:
0 70 N
绝对地址=710
请输入指令的页号、单元号,以及是否为存指令:
4 053 N
out 0
in 4
请输入指令的页号、单元号,以及是否为存指令:
1 50 N
绝对地址=1074
请输入指令的页号、单元号,以及是否为存指令:
5 023 N
out 1
in 5
请输入指令的页号、单元号,以及是否为存指令:
2 15 N
绝对地址=1167
请输入指令的页号、单元号,以及是否为存指令:
1 037 y
out 2
in 1
请输入指令的页号、单元号,以及是否为存指令:
3 21 Y
绝对地址=149
请输入指令的页号、单元号,以及是否为存指令:
2 078 N
out 3
in 2
请输入指令的页号、单元号,以及是否为存指令:
0 56 N
out 4
in 0
请输入指令的页号、单元号,以及是否为存指令:
4 001 N
out 5
in 4
请输入指令的页号、单元号,以及是否为存指令:
6 40 N
out 1
in 6
请输入指令的页号、单元号,以及是否为存指令:
6 084 Y
绝对地址=1236
请输入指令的页号、单元号,以及是否为存指令:
exit
数组 P 的值为:
P[0]=0
P[1]=4
P[2]=6
P[3]=2
五、系统不足与经验体会
系统的不足包括健壮性尚不够好,界面比较简单,对页表的
初始化需要修改程序。
经验体会:注意体会算法的精神,程序前后逻辑要一致。注
意测试时数据的全面性。
六、附录:源代码(带注释)
#include
#include
#define SizeOfPage 100
#define SizeOfBlock 128
#define M 4
struct info//页表
{
bool flag; //标志
long block;//块号
long disk;//在磁盘上的位置
bool dirty;//修改标志
}pagelist[SizeOfPage];
long po;//队列标记
long P[M];
void init_ex1()
{
memset(pagelist,0,sizeof(pagelist));
pagelist[0].flag=1;
pagelist[0].block=5;
pagelist[0].disk=011;
pagelist[1].flag=1;
pagelist[1].block=8;
pagelist[1].disk=012;
pagelist[2].flag=1;
pagelist[2].block=9;
pagelist[2].disk=013;
pagelist[3].flag=1;
pagelist[3].block=1;
pagelist[3].disk=021;
}
void work_ex1()
{
bool stop=0;
long p,q;
char s[128];
do
{
printf("请输入指令的页号和单元号:\n");
if (scanf("%ld%ld",&p,&q)!=2)
{
scanf("%s",s);
if (strcmp(s,"exit")==0)
{
stop=1;
}
}
else
{
if (pagelist[p].flag)
{
printf("绝对地址=%ld\n",pagelist[p].block*SizeOfBlock+q);
}
else
{
printf("* %ld\n",p);
}
}
}while (!stop);
}
void init_ex2()
{
po=0;
P[0]=0;P[1]=1;P[2]=2;P[3]=3;
memset(pagelist,0,sizeof(pagelist));
pagelist[0].flag=1;
pagelist[0].block=5;
pagelist[0].disk=011;
pagelist[1].flag=1;
pagelist[1].block=8;
pagelist[1].disk=012;
pagelist[2].flag=1;
pagelist[2].block=9;
pagelist[2].disk=013;
pagelist[3].flag=1;
pagelist[3].block=1;
pagelist[3].disk=021;
}
void work_ex2()
{
long p,q,i;
char s[100];
bool stop=0;
do
{
printf("请输入指令的页号、单元号,以及是否为存指令:\n");
if (scanf("%ld%ld",&p,&q)!=2)
{
scanf("%s",s);
if (strcmp(s,"exit")==0)
{
stop=1;
}
}
else
{
scanf("%s",s);
if (pagelist[p].flag)
{
printf("绝对地址=%ld\n",pagelist[p].block*SizeOfBlock+q);
if (s[0]=='Y' || s[0]=='y')
{
pagelist[p].dirty=1;
}
}
else
{
if (pagelist[P[po]].dirty)
{
//将更新后的内容写回外存
pagelist[P[po]].dirty=0;
}
pagelist[P[po]].flag=0;
printf("out %ld\n",P[po]);
printf("in %ld\n",p);
pagelist[p].block=pagelist[P[po]].block;
pagelist[p].flag=1;
P[po]=p;
po=(po+1)%M;
}
}
}while (!stop);
printf("数组 P 的值为:\n");
for (i=0;i