1
有实现xy的两个C语言函数如下:
unsigned umul(unsigned x,unsigned y)
{
return xy;
}
int umal(int x,int y)
{
return xy;
}
假定计算机M中ALU只能进行加减运算和逻辑运算,请回答下列问题。
1:若M的指令系统中没有乘法指令,但有加法,减法和移位等指令,则在M上也能实现上述两个函数中的乘法运算,为什么?
我发现408在应用题这块考的是总体把握,很少考具体某个算法的实现。
编译器可以将乘法运算转换成一个循环代码段,在循环代码段中通过比较,加法,移位等指令实现乘法运算
2:若M的指令系统中有乘法指令,则基于ALU,移位器,寄存器以及相应控制逻辑实现乘法操作时,控制逻辑的作用是什么?
控制逻辑的作用为:控制循环次数,控制加法和移位操作。
3:针对以下三种情况:a没有乘法指令,b有使用ALU和移位器实现的乘法指令;c有使用阵列乘法器实现的乘法指令。
函数umul()在那种情况下执行时间最长,哪种最短为什么?
对于a,需要用循环代码段(即软件)实现乘法操作,因而需要反复执行很多条指令。而每条指令都需要取指令,译码,取数,执行并保存结果,所以执行时间很长;
对于b和c,都只要用一条乘法指令实现乘法指令,不过,b中的乘法指令需要多个时钟周期才能完成,而c中的乘法指令可以在一个时钟周期内完成,所以c执行时间最短。
4n位整数乘法指令可保存2n位乘积,当仅取低n位作为乘积时,其结果可能会发生溢出。当n=32,x=2^31-1,y=2时,带符号整数乘法指令和无符号整数乘法指令得到的xy的2n位乘积分别是什么(用十六进制数表示)?此时函数umul()和imul()的返回结果是否溢出?对于无符号整数乘法运算,当仅取乘积的低n位作为乘法结果时,如何用2n位乘积进行溢出判断?
这里是算术移位还是逻辑移位。
这里的移位操作给我移懵逼了,为啥是这样呢?
我们看啊x有32位,是0111 1111 1111 1111 1111 1111 1111 1111
y也有32位,是0000 0000 0000 0000 0000 0000 0000 0010
当x和y是无符号整数的时候,乘起来很容易,无非是把x都左移一位,然后右边补0就是了。
可当它们都是有符号整数的时候,符号位到底变不变,这就成为了一个问题。
我通过查阅资料,了解到了具体规则:
对有符号正数进行左移和右移,都不需要顾及到符号位。并且因为正数的原码,补码,反码相同的原因,补0就可以了。
首先,我原来有一个错误的认知,就是对于有符号数而言,无论是左移还是右移,无非都是乘2除2罢了,所以我以为符号位是不动的。
但这种想法是错误的,因为移位是宏观的操作,不允许任何元素保持不动,所以左移的时候,正数有可能变成负数,负数有可能变成正数。因为左移的话,原来的符号丢了,右边补的是0。
那为什么要容许这种现象存在呢?这样不会导致数据运算错误吗?事实上它代表溢出。
而当右移时,符号位看上去不会变化,实际上只是补上对应的符号位罢了。
我现在只能分析到这了。
当x和y都是有符号整数时:
x整体左移一位,低位补0
1111 1111 1111 1111 1111 1111 1111 1110
原本的符号位是0,现在符号位变成1了,很明显溢出。
对于无符号整数乘法,若乘积高n位全为0,则不溢出,否则溢出。
2
假定主存地址为32位,按字节编址,指令Cache和数据Cache与主存之间均采用8路组相联映射方式,直写(Write Through)写策略和LRU替换算法,主存块大小为64B,数据区容量各为32KB,开始时cache为空。
(1)Cache每一行中标记(Tag),LRU位各占几位?是否有修改位?
第一点,我忘记了什么是标记。因为这个名字起的太模糊了。现在重申一下,
标记是Cache的前n位,表示的是它是主存中哪一块的副本,是CPU访存时从Cache调取数据块的一个确认机制。如果Cache的标记和主存地址的高t位标记进行比较,若相等且有效位为1,则访问Cache“命中”。
Cache的结构分为三部分,标记,组号,块内地址。只有标记最难以理解,要多加记忆。
主存块大小为64B=2^6字节,故主存地址低6位为块内地址;
什么叫8路组相联映射方式,实际上就是一个组内有8个块。可以这样记忆,二路组相联映射方式就是一个组有两个块。
Cache组数为32KB/(64B*8)=64=2^6,故主存地址中间6位为Cache组号。主存地址为32位,那么剩下的20位就是标记了。
采用的是8路组相联映射,因此只需要用3位LRU位就能表示所有的块。
写策略,这点还要强调一下。
关于Cache写策略,我们要明确一点,到底什么是Cache写。Cache写问题就是到底通不通知内存的问题。
因为Cache中的内容是主存块副本,当对Cache中的内容进行更新时,就需选用写操作策略使Cache内容和主存内容保持一致。
全写法(write-through)和写回法(write-back)的最主要区别就是,write-back有修改位,全写法没有。这是因为全写法是很正常的内存同步机制,当Cache发生变化时通知主存。常规方法往往显得笨重,比如write-through就是增加了访存次数,降低了Cache的效率。因为Cache和主存之间的速度有差异,为了匹配它们的速度,又增加了一个写缓冲(write buffer)
对于写回法而言,它取了个巧。当CPU对Cache写命中时,只修改Cache的内容,而不立即写入主存,只有当此块被换出时才写回主存。这样子减少了访存的次数,但也必须增加修改位。可以说剑走偏锋。
还有一些进阶的知识,那就是CPU访问Cache时,找到对应的块了,那使用write-through或write-back就行,但要是没有找到对应的块呢?是不是需要修改主存里的块。
这里面又有一个省事的办法和费力地办法。
省事的办法就是非写分配法(not-write-allocate),就是CPU去Cache里没有找到对应的块,这时候直接把内容写入主存,就不管Cache了。
非写分配法和全写法通常一起使用,大概是因为他俩都是没有取巧的方法。
费力的办法就是写分配法,就是加载主存中的块到Cache中,然后更新这个Cache块。它试图利用程序的空间局限性,但缺点是每次不命中都需呀从主存中读取一块。
写分配法(write-allocate)通常和写回法(write-back合用,大概是因为它们都是取巧的办法。
(2)
有如下c语言段:
for(k=0;k<1024;k++)
s[k]=2*s[k];
若数组s及变量k均为int型,int型数据占4B,变量k分配在寄存器中,数组s在主存中的起始地址为0080 00C0H,则该程序段执行过程中,访问数组s的数据Cache缺失次数为多少?
数组s的起始地址为0080 00C0,题中给出这段信息的目的是什么我一开始没有理解,现在我知道了。
0000 0000 1000 0000 0000 0000 1100 0000
这一共是32位,标识位是 0000 0000 1000 0000 0000,这个在本题中并没有用处。组号是0000 11,这个在本题中也没有用处。
但是块内地址0000 00这个在本题中就有用处了,他告诉我们s是在一个主存块开始处。
我们仔细分析这段C语言代码就会发现:
这段代码运行了1024次,每一次都要读一次s,写一次s。
也就是说要访问数组s的数据Cache2048次,一个数组块大小为64B,一个int型数据4B,一个块足可以支持代码循环16次,访问Cache32次。
这其中,只有第一次访问Cache时会缺失,其余的三十一次均不会确实,Cache缺失率为1/32。
因此访问数组s的数据Cache缺失次数为2048*(1/32)=64次
(3)
若CPU最先开始的访问操作是读取主存单元0001 0003 H中的指令,简要说明从Cache中访问该指令的过程,包括Cache缺失处理过程。
0001 0003H = 0000 0000 0000 0001 0000 0000 0000 0011B,根据主存地址划分可知,组索引为0,故该地址所在主存块被映射到指令Cache第0组;因为Cache初始为空,所有Cache行的有效位均为0,所以Cache访问缺失。此时,将该主存块取出后存入指令Cache第0组的任意一行,并将主存地址高20位(00010H)填入该行标记字段,设置有效位,修改LRU位,最后根据块内地址000011B从该行中取出相应内容。
老实讲这个流程我记得不是很清楚,这里要重点记忆一下。
谁被访问过谁优先级高,这是那个什么改进过的block算法。
3
现有5个操作A,B,C,D和E,操作C必须在A和B完成后执行,操作E必须在C和D完成后执行。请使用信号量的wait(),signal()操作,PV操作描述上述操作之间的同步关系,并说明所用信号量和初值。
5个操作比较复杂,我先选3个ABC试一下。
semaa=1
semab=1
semac=2
wait(semaa)
semac-1
signal(semaa)
有点迷惑了,我要看一下怎么写的。
我以前只知道可以设置信号量来控制某个操作,但不知道原来可以设置一个信号量控制两个操作。
我发现关于信号量我理解的很不到位,首先wait和signal是干嘛的?它是负责允许某个操作执行与否的一个守卫,对,它其实就是门卫。
我们可以看一下代码
wait(S){
while(S<=0);
S=S-1;
}
首先分析wait代码,当S=1时,会跳出while的循环,S-1就代表允许操作执行;当S=0的时候,它会一直卡在while循环这里,表示不允许执行操作。
其实可以理解成门卫守护着仓库的大门,S=1时,就允许别人去仓库拿货物;当S=0时,就不允许别人去仓库拿货物。
接下来我们再看signal操作代码
signal(S){
S=S+1;
}
它比起wait简单了一些。其实就是门卫允许你拉货物进仓库。
在计算机中任何东西的发明都是为了解决问题的,比如信号量它就是用来实现同步和互斥的。
什么叫同步,你比如说,进程P2中的y操作要使用进程P1中的x操作得到的运行结果,所以就必须在P1进程完成后通知P2进程,告诉他可以运行了,这样才不会发生错误。
既然是要通知,那就得有公共信号量吧。
所以实现进程同步的算法就是:
semaphore S=0;
P1(){
x;
V(S);其实这里的V操作是很容易让人迷惑的,我们学的不都是先P再V吗?这是因为先P再V是最基础的操作,考研当然不可能考这个了。
细细分析,P1进程的实现需要得到允许吗?并不需要,本题的限制只有一个,就是P2要在P1以后执行。所以P1需要P操作,需要得到门卫许可吗?当然不需要,它只需要通过V操作来通知P2可以运行了。
}
P2(){
P(S);
y;
}
进程互斥:
比起同步而言,实现互斥的流程就很符合正常认知了。
semaphore S=1;
P1(){
P(S);
进程P1的临界区;
V(S);
}
P2(){
P(S);
进程P2的临界区;
V(S);
}
利用信号量来实现同步与互斥还是大家能猜到的,可它居然还能用来实现前驱关系,这就是我没有想到的了。
Semaphore Sac = 0;
Semaphore Sbc = 0;
Semaphore Sce = 0;
Semaphore Sde = 0;
Cobegin
Begin操作 A;signal(Sac);End
Begin操作B;signal(Sbc);End
Begin wait(Sac);wait(Sbc);操作C;signal(Sce);End
Begin 操作D;signal(Sde);End
Begin wait(Sce);wait(Sde);End
CoEnd
4
要使用虚拟内存?
因为传统的内存管理策略有缺点,什么缺点?作业必须一次性全部装入内存后,才能开始运行。这会导致两种情况。1当作业很大而不能全部被装入内存时,将使该作业无法运行;2当大量作业要求运行时,由于内存不足以容纳所有作业,只能使少数作业先运行,导致多道程序度的下降。
也就是说传统的内存管理作业很僵化,很机械,导致内存处理作业的能力下降。
其次,由于作业被装入内存后,就一直驻留在内存中,其任何部分都不会被换出,直至作业运行结束。运行中的进程会因为等待I/O而被阻塞,可能长期处于等待状态。
总结一下,就是传统的内存管理策略速度又慢又容易卡壳。
所以我们就创造了虚拟内存这种办法来提升速度避免阻塞。
虚拟存储器是基于局部性原理的,基于局部性原理,当程序装入时,将程序的一部分装入内存,而将其余部分留在外存,就可以启动程序执行。
虚拟存储器的大小由计算机的地址结构决定的,并不是内存和外存的简单相加。
这句话其实很有玄机,我记得有一道题就是这样。比如计算机有32位,内存8G,外存256G,虚拟存储器的大小是多少?
按照常理来看,那不就是8+256吗,但这就是出题人挖的坑,虚拟地址存储器的大小实际上是2^32 单位我记不清了。
虚拟内存的实现需要建立在离散分配的内存管理方式的基础上。
为什么连续分配就不行呢?因为连续分配的话会使相当一部分内存空间都处于暂时或“永久”的空闲状态,造成内存资源的严重浪费。
虚拟内存技术的实现需要基于以下几种机制,分别是
页表机制(或段表机制),作为主要的数据结构。
中断机构,当用户程序要访问的部分尚未调入内存时,则产生中断。
地址变换机构,负责逻辑地址到物理地址的变换。
我又有一个问题,什么叫二级页表。
我们得先知道什么是页表,这就要提起什么是非连续存储,什么是连续存储了。按照常理而言,内存分配就是排排坐吃果果,都是极有规律的,但是在实际使用中,就像是传统的内存管理方式速度慢且卡壳一样,我们发现即使内存中还剩余着较多的空间,但无法放入一些大文件,我们这是因为内存碎片化严重,连续的内存空间比较小导致的,由此我们提出了非连续存储结构。
有句话叫人有所得必有所失,非连续存储结构也是这样,它需要额外的空间去存储分散区域的索引,因此密度低于连续存储。
有一句话我无法理解,什么叫 固定分区会产生内部碎片,动态分区会产生外部碎片?
我看了别人的文章之后有了一点理解,首先内部碎片和外部碎片都是对内存的浪费,之所以一个叫内部另一个叫外部,是相对于分区而言的。固定分区与动态分区的区别是,在动态分区中,系统划分给作业的分区长度等于作业大小,在分区中不会产生多余的空间,但在分区外就可能产生小的分区碎片,因为太小而无法使用,我们称之为外部碎片。
内部碎片则是因为固定分区中,系统分配给分区的作业往往要小于分区的大小,这样就导致了浪费,我们称之为内部碎片。
说到二级页表,必须先提起基本分页存储管理方式。首先我们知道一件事,那就是基本分页管理方式必定是有进步的,它的进步就是碎片更小了。
页的地址结构包括两部分,分别是页号和页内地址。
通过地址结构,我们已经知道了逻辑地址,那接下来如何知道物理地址呢?
这就要借助页表了,页表包括页号和页内偏移量。它是为了便于在内存中找到进程的每个页面所对应的物理块。页表项的第二部分与地址结构的第二部分共同组成物理地址。
总的而言,页表的作用是实现页号到物理块号得地址映射。
这么说太枯燥了,我举一个例子,以32位逻辑地址空间,页面大小4KB,页表项大小为4B为例。那么页表项有多少个呢?我们都知道页表项的第一部分是页号,也就是说它有多少页,那就该有多少页表项。
逻辑地址空间为2^32B,页面大小 212B,那么一共有232 / 212=220页。
我们运算着运算着发现不对,这页数也太多了吧,要知道我们实际运行的时候只需要几十个页面,所以为了压缩页表,我们进一步延申页表映射的思想,这样就得到了二级页表。
二级页表其实就是页表的页表,地址结构为
一级页号,二级页号,页内偏移
某32位系统采用基于二级页表的请求分页存储方式,按字节编址,页目录项
和页表项长度均为4字节,虚拟地址结构如下所示。
页目录号(10位),页号(10位),页内偏移量(12位)
某c程序中数组a[1024] [1024] 的起始虚拟地址为1080 0000H,数组元素占4字节。该程序运行时,其进程的页目录起始物理地址为0020 1000H,请回答以下问题。
(1)数组[1][2]的虚拟地址是什么?对应的页目录号和页号分别是什么?对应的页目录项的物理地址是什么?若该页目录项中存放的页框号为00301H,则a[1][2]所在页对应的页表项的物理地址是什么?
为什么
首先,我们知道c语言数组以[0][0]开头,要求a[1][2]的虚拟地址就要知道它们之间相差多少个数组元素。我们知道页内偏移量为12位,也就是说一页有2^12B,一个数组元素占4B,也就是说一页有
2^10个元素。那么a[1][2]的虚拟地址就为1080 0000 + (11024+2) 4=
1080 0000 + 1026*4=1080 0000 + 4104
这个所谓的4104是十进制数,如果将其变为16进制数的话那就是2008
用短除法将10进制数转化为16进制数
4104/16=256………………余数为8
256/16=16………………余数为0
16/16=1………………余数为0
1/16=1………………余数为1
将余数颠倒,4104转化为的16进制数就是1008
那么a[1][2]的虚拟地址就是1080 0000 + 0000 1008 = 1080 1008
它的二进制表示为 0001 0000 1000 0000 0001 0000 0000 1000
页目录号为 0001 0000 10,即0000 0100 0010,也就是042H
页号为0000 0000 0001,即001H
我们知道页目录起始物理地址为0020 1000H,首先明确一点,它这里的页目录项其实指的是一级页号,并且一个一级页号为4B。我们知道1080 1008的页目录号为042H,也就是说它的物理地址为
十六进制的运算确实麻烦42就是416+21=66
66*4 = 264D转化为16进制为108H
0020 1000 + 42*4 =0020 1000 + 108 = 0020 1108H这道题告诉我们一件事情16进制和10进制不要直接运算,很容易发生错误,最好把它们都转化为10进制再进行运算。
什么是页框号?
页框号就是物理块号。
页表项的物理地址是什么?
页表项的第二部分页框号(物理块号)与地址的第二部分页内偏移共同组成物理地址。
这两个地址好像一个说的是页的地址,一个说的是页内地址,太容易搞混了。
页表项的物理地址是0030 1000H + 4*1H 0030 1004H
(2)数组a在虚拟地址空间中是否必须连续,在物理地址空间中是否必须连续。
数组具有随机存取的特点,数组a在虚拟地址空间中所占的空间一定是连续的,在分页管理中,数组并不一定在同一个页中,,而逻辑上相邻的两个页,在物理上不一定相邻,因此数组a在物理地址空间中不一定连续。
(3)
已知数组a按行优先方式存放,若对数组a分别按行遍历和按列遍历,则哪一种遍历方式的局部性更好?
行优先就是a[0][0],a[1][0],a[2][0],a[3][0]
列优先就是a[0][0],a[0][1],a[0][2],a[0][3]
行优先更好,因为访问的都是同一个页中的内容。
5
某校园网有两个局域网,通过路由器R1,R2和R3互联后接入Internet,S1和S2为以太网交换机。局域网采用静态IP地址配置,路由器部分接口以及各主机的IP地址如图所示。
假设NAT转换表结构为:
外网 内网
IP地址 端口号 IP地址 端口号
(1)为使H2和H3能够访问Web服务器(使用默认端口号),需要进行什么配置?给出具体配置。
这里我不是很清楚端口号。
我看的视频中说,因为Web服务器使用的是HTTP协议,即超文本传输协议,因此端口号为80。
那么NAT的配置为:
外网 内网
IP地址 端口号 IP地址 端口号
203.10.2.2 80 192.168.1.2 80
(2)
若H2主动访问Web服务器时,将HTTP请求报文封装到IP数据报P中发送,则H2发送的P的源IP地址和目的IP地址分别是什么?经过R3转发后,P的源IP地址和目的IP地址分别是什么?经过R2转发后,P的源IP地址和目的IP地址分别是什么?
H2源IP 192.68.1.2
H2目的IP203.10.2.2
R3源IP地址203.10.2.6
R3目的IP地址203.10.2.
R2源IP地址203.10.2.6
R2目的IP地址192.168.1.
本文探讨了在不同指令系统下实现乘法运算的方法,包括如何在无乘法指令的环境下利用加法和移位完成乘法。同时,讨论了在有乘法指令时,控制逻辑在实现乘法操作中的作用。文章还涉及了乘法运算的时间复杂度对比,指出无乘法指令时执行时间最长,阵列乘法器实现的乘法指令执行时间最短。此外,文章分析了带符号和无符号整数乘法的溢出判断,以及数据Cache的管理,包括标记、LRU位、写策略。最后,文章介绍了虚拟内存的概念,讨论了其必要性和工作原理,以及二级页表的使用情况。
1万+

被折叠的 条评论
为什么被折叠?



