计算机组成原理这门课算是CS专业当中比较主要核心的一门课,博主把自己对这门课相关知识点的理解做了一个总结,若有不当或不同观点的地方,可与博主一起华山论剑。
第一代:电子管计算机(1946-1958年):
硬件方面,逻辑元件采用的是真空电子管,主存储器采用汞延迟线、阴极射线示波管静电存储器、磁鼓、磁芯;外存储器采用的是磁带。软件方面采用的是机器语言、汇编语言。应用领域以军事和科学计算为主。
电子管计算机我们可以想象一下,一看就算那种体积超大的大老粗版本的计算机,价格昂贵,电路极其复杂,空间占用大,功耗大,速度慢,操作复杂。但是这也为以后的计算机发展奠定了基础。
第二代:晶体管计算机(1958-1964年):
硬件方的操作系统、高级语言及其编译程序。应用领域以科学计算和事务处理为主,并开始进入工业控制领域。
这个相比之前的电子管计算机肯定是针对它的缺点进行了相应的优化,体积进行了相应的缩小,能耗降低,速度增快(一般为每秒数10万次,可高达300万次),操作相对也简单了,更加可靠。但是呢,这个仍然无法进入家家户户,无法普遍使用,只能普及到工业界当中。
第三代:集成电路计算机(1964-1970年):
硬件方面,逻辑元件采用中、小规模集成电路(MSI、SSI),主存储器仍采用磁芯。软件方面出现了分时操作系统以及结构化、规模化程序设计方法。
可以想象,这个将大量晶体管集成起来,肯定会使得体积大大减小,速度进一步加快(一般为每秒数百万次至数千万次),可靠性进一步提高,成本降低,价格降低,产品进一步走向通用化,系列化,应用领域开始由工业领域进入文字处理和图形图像处理领域,这也导致了操作系统的产生。
第四代:超大规模集成电路计算机(1970年-至今):
硬件方面,逻辑元件采用大规模和超大规模集成电路(LSI和VLSI)。软件方面出现了数据库管理系统、网络管理系统和面向对象语言等。特点是1971年世界上第一台微处理器在美国硅谷诞生,开创了微型计算机的新时代。应用领域从科学计算、事务管理、过程控制逐步走向家庭。
此时计算机变得体积更加小,价格更低,适用于普通大众,开始逐渐走向家家户户。
第五代:未来计算机(未来):量子计算机和生物计算机
量子计算机(quantum computer)是一类遵循量子力学规律进行高速数学和逻辑运算、存储及处理量子信息的物理装置。当某个装置处理和计算的是量子信息,运行的是量子算法时,它就是量子计算机。量子计算机的概念源于对可逆计算机的研究。研究可逆计算机的目的是为了解决计算机中的能耗问题。
量子计算机的特点主要有运行速度较快、处置信息能力较强、应用范围较广等。与一般计算机比较起来,信息处理量愈多,对于量子计算机实施运算也就愈加有利,也就更能确保运算具备精准性。
生物计算机也称仿生计算机,主要原材料是生物工程技术产生的蛋白质分子,并以此作为生物芯片来替代半导体硅片,利用有机化合物存储数据。信息以波的形式传播,当波沿着蛋白质分子链传播时,会引起蛋白质分子链中单键、双键结构顺序的变化。运算速度要比当今最新一代计算机快10万倍,它具有很强的抗电磁干扰能力,并能彻底消除电路间的干扰。能量消耗仅相当于普通计算机的十亿分之一,且具有巨大的存储能力。生物计算机具有生物体的一些特点,如能发挥生物本身的调节机能,自动修复芯片上发生的故障,还能模仿人脑的机制等
目前量子计算机也已经研发出来了,相信会不断改进,降低成本体积,逐渐进入到家家户户当中。
超级计算机:通常是指由数百数千甚至更多的处理器(机)组成的、能计算普通PC机和服务器不能完成的大型复杂课题的计算机。超级计算机是计算机中功能最强、运算速度最快、存储容量最大的一类计算机,是国家科技发展水平和综合国力的重要标志。比如说我们的超算中心。
大型计算机:计算机中通用性能最强,功能、速度、存储量仅次于超算机的一类计算机,国外习惯上将其称为主机(Mainframe)。大型机具有比较完善的指令系统和丰富的外部设备,很强的管理和处理数据的能力,一般用在大型企业、金融系统、高校、科研院所等。
服务器:可以被网络用户共享、为网络用户提供服务的一类高性能计算机。一般都配置多个CPU,有较高的运行速度,并具有超大容量的存储设备和丰富的外部接口。比如说阿里云,腾讯云这类云服务器。
小型机:计算机中性能较好、价格便宜、应用领域非常广泛的一类计算机。其浮点运算速度可达每秒几千万次。小型机结构简单、使用和维护方便,备受中小企业欢迎,主要用于科学计算、数据处理和自动控制等。
微型计算机:就是我们现在用的台式电脑,笔记本电脑。
1.特点: 程序指令和存储器一起存储。
2.基本组成: 由存储器,运算器,控制器(运算器和控制器为CPU),输入设备,输出设备。
存储器:长期记忆程序,数据,中间运算结果以及最终运算结果,方便下一步的处理,会影响输出。
控制器,运算器:具备算数,逻辑运算,数据传送等数据加工的能力
输入设备:把需要的程序和数据送给计算机处理
输出设备:按要求把处理的结果输出给用户
3.工作原理: 采用二进制,**程序指令和数据一起存储。**按程序编排的顺序,一步一步地取出指令,自动地完成指令规定的操作
4.相对之前计算机的改进: 之前的计算机一般都仅含固定程序,改程序就必须得改结构,重新设计电路,非常的不方便,而计算机的发展则是朝着让人更加舒服方便的方向发展,因此冯诺依曼机就算把程序存储起来,设计通用电路,使得可以轻易的改变程序,更加灵活方便。
5.冯诺依曼瓶颈: 从上面的基本组成我们可以看出,CPU和存储器是分开来的,而CPU的运算处理速度非常的快,但是呢,存储器相对来说,接收数据速度比较慢,就造成了CPU经常空转等待数据传输,极大的浪费了资源等问题,也就是说CPU与存储器之间的性能问题。 这个瓶颈也对现代计算机产生了重大的影响,促使了缓存架构的开发。
相对冯诺依曼体系做出了重大改进,突破了冯诺依曼瓶颈,把存储器放入了CPU当中,解决了CPU与存储器之间的性能问题。
1.概述: 假设L1为高级的计算机程序语言,L0为低级计算机程序语言
2.区别:
程序翻译是由一种语言直接生成另外一种语言,而解释器则不直接生成
解释过程由L0编写的解释器取解释L1程序,而程序翻译过程则是由编译器直接生成L0。
3.特例: 有的程序语言比较特殊,是翻译,解释一起运行,比如说Java,C#语言。以Java语言为例,Java语言编写的程序会首先通过程序翻译编译成JVM字节码,然后JVM字节码才会通过解释器解释为机器码进行相应的程序执行。
1.计算机层次组成(自底向上): 硬件逻辑层,微程序机器层,传统机器层(这三个称为实际机器),操作系统层,汇编语言层,高级语言层(系统软件层),应用层(应用软件层)。
!!!注:不同架构CPU对应着不同的CPU指令集,一条机器指令对应一个微程序,但是一个微程序对应一组微指令。
1.容量单位:
bit | Byte | KB | MB | GB | TB | PB | EB |
---|---|---|---|---|---|---|---|
最小 | 8 bits | 1024 B | 1024KB | 1024MB | 1024GB | 1024TB | 1024PB |
门电路 | 寄存器 | 高速缓存 | 内存/硬盘 | 硬盘 | 云硬盘 | 数据库 |
2.速度单位:
1.ASCII码: 由大写字母,小写字母,符号,数字组成,其中编码是7个字节,含有95个可打印字符和33个不可打印字符,总共128个,128=2^7,因此7个字节足够,但是很多应用和国家当中的符号无法使用其进行表示。因此有了:
2.扩展的ASCII码: 编码扩展为8个字节,加入了数字运算符,带音标的欧洲字符。
3.GB2312码: 含有7445个字符,6763个汉字,682个其他符号,可以看来,这个字符编码还是比较完备的,但是呢,其又不符合国际标准因此后面也被抛弃了。
4.GBK码: 向下兼容GB2312,向上支持ISO国际标准,收录了21003个汉字,支持中日韩文字,一般来说Windows默认使用GBK编码。
5.Unicode: 又称为统一码,万国码,世界通用,使用UTF系列实现,UTF-8以字节单位对Unicode进行存储。记住!!!UTF-8不等同于Unicode。一般来说,编程推荐使用utf-8.
1.功能概述: 解决不同设备之间的通信问题
2.分类:
A.片内总线:顾名思义,也就是芯片内部的总线,比如说连接芯片内部的寄存器,运算器之间,主要还是简化内部结构。
B.系统总线:
数据总线:一般与CPU位数相同,可以双向传输各个部件的数据,而且其位数是一个衡量总线质量性能的重要参数。
地址总线:用于数据寻址,比如说地址总线位数为n,那么它寻址的范围是0~2^n,它可以指定数据在内存当中的地址。
控制总线:可以发出各种控制信号,并且监视不同组件之间的状态。
关键点来了!!!!
3.总线的仲裁: 总线可以连接多个设备,但是当多个设备同时使用总线的时候,不可避免的会产生冲突,未来解决这个问题,就有了总线的仲裁方案。
链式查询法:
以上图为例,当I/O设备1需要使用总线的时候,它会发送请求信号给总线控制器,也就是仲裁器,之后仲裁器会发送"同意"信号,依次结果0->1->2设备,若设备0无请求,那么信号会继续到达下一个I/O设备,设备接收到同意信号以后就会占用总线进行使用。当然如果之前设备0就已经发出过请求了,那么就是设备0的使用优先级更加高,使用优先级按照链式依次递减。电路因此缺点也就出来了,这会使得优先级比较低的设备难以获得总线使用权,并且只要有一个设备故障,那么对整体造成的影响就比较大,对故障比较敏感。 当然这种方法比较简单,相应的电路复杂度也比较低,成本也低。
计数器定时查询法:
以上图为例,仲裁控制器会对每一个设备进行编号,使用计数器进行计数,当接收到请求信号的时候,会往所有的设备发送计数值,当计数值与编号一致的的时候,则设备可以获得总线的使用权。过程有点麻烦,电路也相对复杂,但是可以通过编号改变优先级。
独立请求法:
以上图为例,每个IO设备都会独立连接仲裁器,设备可以单独向仲裁器发送请求和接收信号,当有多个设备发送请求的时候,仲裁器可以有权分配优先级使用权。这会使得响应速度变快,改变优先级比较方便,对电路故障的敏感度也相对较低,但是连线较多,成本高,比较复杂。
1.常见的输入输出设备:
字符输入设备:比如说有键盘
图像输入设备:鼠标,输入板,扫描仪
图像输出设备:显示器,打印机,投影仪
2.接口的通用设计: 为了使计算机能够读取,发送数据,判断设备是否被占用,是否已经连接,启动等等。
数据线:使得计算机能够和IO设备进行数据交换,即读取,发送数据
状态线:判断设备是否已经被占用,是否已经正常连接
命令线:发送读写信号,发送启动停止信号
设备选择线:对连在总线上的设备进行选择
3.CPU与IO设备的通信方法(输入输出):
程序查询方式:是完全通过程序来控制主机和外围设备之间的信息传送。
通常的办法是在用户的程序中安排一段由输入输出指令和其他指令所组成的程序段直接控制外围设备的工作。也就是说CPU要不断地查询外围设备的工作状态,一旦外围设备“准备好”或“不忙”,即可进行数据的传送。该方法是主机与外设之间进行数据交换的最简单、最基本的控制方法。
程序中断方式:当外围IO设备准备就绪的时候,向CPU发送中断信号,CPU有专门的电路响应中断信号。
DMA方式:在外围设备和主存之间开辟直接的数据通路。在正常工作时,所有的工作周期均用于执行CPU的程序。当外围设备完成I/O的准备工作后,占用CPU的工作周期,和主存直接交换数据。完成后,CPU又继续控制总线,执行原程序。完成这项工作的是系统中增设的DMA控制器。
这三种方式的区别:
(1)程序查询、程序中断方式的数据传送主要依赖软件,DMA主要依赖硬件。 (注意:这里指主要的趋势)
(2)程序查询、程序中断传送数据的基本单位为字或字节,DMA为数据块。
(3)程序查询方式传送时,CPU与I/O设备串行工作;程序中断方式时,CPU与I/O设备并行工作,现行程序与I/O传送串行进行;DMA方式时,CPU与I/O设备并行工作,现行程序与I/O传送并行进行。
(4)程序查询方式时,CPU主动查询I/O设备状态;程序中断及DMA方式时,CPU被动接受I/O中断请求或DMA请求。
(5)程序中断方式由于软件额外开销时间比较大,因此传输速度最慢;程序查询方式软件额外开销时间基本没有,因此传输速度比中断快;DMA方式基本由硬件实现传送,因此速度最快;
注意:程序中断方式虽然CPU运行效率比程序查询高,但传输速度却比程序查询慢。
(6)程序查询接口硬件结构最简单,因此最经济;程序中断接口硬件结构稍微复杂一些,因此较经济;DMA控制器硬件结构最复杂,因此成本最高;
(7)程序中断方式适用于中、低速设备的I/O交换;程序查询方式适用于中、低速实时处理过程;DMA方式适用于高速设备的I/O交换;
1.分类:
存储介质 | 存取方式 | ||
---|---|---|---|
半导体存储器 | U盘,内存等等 | RAM | 随机存取,与位置无关 |
磁存储器 | 磁盘磁带等等 | ROM | 只读不写 |
串行存储器 | 按顺序存储,与位置有关 |
2.层次结构:
缓存 | 高速缓存 | 速度快,位价高 |
---|---|---|
主存 | 内部存储 | 速度中,位价中 |
辅存 | 外部存储 | 速度低,位价低 |
其中,在主存和CPU之间加一个高速缓存为缓存-主存层次结构,其原理为局部性原理,即计算机CPU在访问存储器的时候,所访问的存储单元会趋于聚集在一个较小的连续区域,这个可以解决主存速度不足的问题,当然,为了解决主存容量不足的问题,还引入了主存-辅存结构,即在外部加一个辅存。
1.概述:
主存:主存,又称内存,是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。 内存(Memory)也被称为内存储器,其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据
辅存:狭义上就是我们所说的硬盘,即外部存储器,存储容量大,比如说有磁存储器,光盘存储器等等。
2.举例说明:
3.磁盘访问算法: 假设上图的磁头在第四磁道,从内向外以此为1,2,3,4,5,6磁道,磁头径向为内->外。
假设我们要访问1,4,5,2,3磁道
先来先服务算法:根据我们需要访问磁道的顺序依次访问,谁先在前面就访问谁,因此访问顺序为1,4,5,2,3
最短寻道算法:顾名思义,就是寻找附件距离最短的磁道,因此访问顺序为:4 5 3 2 1
扫描算法:每次扫描只往一个方向移动,达到所需服务尽头的时候,返回,即反方向移动。因此访问顺序为:4 5 3 2 1
循环扫描算法:只往一个方向读取,到达尽头,从另外一边尽头继续按照原方向访问,访问顺序为:4 3 2 1 5
1.了解:
字:存放在一个存储单元当中的二进制组合
字块:连续的存储单元,包换多个字
字的地址:前m位是字块的地址,后b位是字在字块中的地址
2.命中率和访问效率:
命中率:衡量缓存性能的重要指标
设命中率位h,访问缓存的次数位Nc,访问主存的次数位Nm,则h=Nc/(NC+Nm)
访问效率:假设访问缓存的时间位tc,访问主存的时间位tm,访问效率为e。
e=tc/(h*tc+(1-h)*tm),其中分母是平均访问时间。
为了提高命中率和访问效率,我们就得需要性能良好的缓存替换策略,让CPU需要的数据尽量在缓存当中。
重点来聊!!!
3.缓存替换策略算法(面试考点):
from DoubleList.DoubleList import DoubleList,Node //自己先前写了一个双向链表和节点Node类
class FIFO:
def __init__(self,capacity):
self.capacity=capacity
self.size=0
self.map={} //缓存映射到map当中
self.list=DoubleList(self.capacity)
def get(self,key): #返回对应key值所对应的value
if key not in self.map: //如果找的key值不在缓存当中
return -1
else:
node = self.map.get(key) //如果在缓存当中,则返回key对应的value值
return node.value
def put(self,key,value):
if self.capacity==0:
return
if key in self.map: //如果需要的数据已经在缓存当中了,那么就将原来的删掉,并且移到最后面去。
node=self.map.get(key)
self.list.remove(node)
node.value=value
self.list.append(node)
else:
if self.size==self.capacity: //如果缓存当中没有并且缓存满了,淘汰最前面的,也就是最近最少出现的数据,并且把需要的数据加入到后面
node = self.list.pop()
del self.map[node.key]
self.size-=1
node=Node(key,value) //如果缓存没满,直接往后面加入数据
self.list.append(node)
self.map[key]=node
self.size+=1
def print(self):
self.list.print()
if __name__=='__main__':
cache= FIFO(2)
cache.put(1,1)
cache.print()
cache.put(2,2)
cache.print()
print(cache.get(1))
cache.put(3,3)
cache.print()
print(cache.get(2))
cache.print()
cache.put(4,4)
cache.print()
print(cache.get(1))
大家也可以验证一下,如果说有兴趣的话,读者可以自己按照这个思路用Java,C++或者python语言重新实现一下。
# ! _*_ encoding=utf-8 _*_
from DoubleList.DoubleList import DoubleList,Node
class LRU:
def __init__(self,capacity):
self.capacity=capacity
self.size=0
self.map={}
self.list=DoubleList(self.capacity)
def get(self,key):
if key in self.map: //如果访问的节点在缓存里面已经有,则置前
node = self.map[key]
self.list.remove(node)
self.list.append_front(node)
return node.value
else:
return -1
def put(self,key,value):
if key in self.map: //置前操作
node = self.map[key]
self.list.remove(node)
node.value=value
self.list.append_front(node)
else: //淘汰最近最少使用的节点,把当前节点加入到最前面。
node = Node(key,value)
if self.list.size >=self.capacity:
node1=None
oldNode = self.list.remove(node1)
self.map.pop(oldNode.key)
self.list.append_front(node)
self.map[key] = node
def print(self):
self.list.print()
if __name__ =='__main__':
cache = LRU(2)
cache.put(1,1)
cache.print()
cache.put(2,2)
cache.print()
cache.put(3,3)
cache.print()
cache.get(2)
cache.print()
cache.get(3)
cache.print()
cache.get(1)
cache.print()
print(cache.get(1))
1.机器指令:主要由操作码,地址码组成。前者指明指令需要完成的操作,后者给出操作数的地址或者直接给出操作数。而这个地址指令可以分为三地址指令,二地址指令,一地址指令和零地址指令。
操作码(OP) | addr1 | addr2 | addr3 |
---|
操作码(OP) | addr1 | addr2 |
---|
操作码(OP) | addr1 |
---|
2.机器指令的操作类型:数据传输,算术逻辑,移位逻辑,控制指令。
3.寻址方式:
指令寻址:分为顺序寻址和跳跃寻址。前者就是按照地址的顺序依次查找下去,后者则是查找过程中遇到了JMP条约指令,条约到指定的地址。
数据寻址:分为立即寻址(指令里直接给出操作数,无需通过地址,寻址速度快,但是地址码的位数限制了操作数的范围),直接寻址(即直接给出操作数在内存当中的地址,使得寻找操作数简单,但是地址码的位数限制了操作数地址码的范围),间接寻址(即给出了操作数地址的地址,需要经过多次寻址,这可以使得范围更加大,但是速度较慢)
1.组成:程序计数器,时序发生器,指令译码器,各种寄存器(通用寄存器,指令寄存器,主存数据寄存器,主存地址寄存器),总线。
程序计数器:存储下一条指令的地址,循环从中拿出指令,指令被拿出时,指向下一条指令。
时序发生器:可以发射时序脉冲,使得CPU工作更加有节奏
指令译码器:翻译操作码对应的操作,控制传输地址码对应的数据
指令寄存器:从主存或者缓存当中取出指令,使CPU高速高效运转
通用寄存器:保存ALU运算的中间结果,暂时存放或者传送该数据,并且等待下一个控制信号,把数据送到指定位置。
另外两个通俗易懂,顾名思义,就不多说了。
1.组成:数据缓存器,ALU,通用寄存器,状态字寄存器,总线。
数据缓存器:分为输入缓存和输出缓存,暂时存放送入的数据和送出的数据,并且等待下一条指令,把该数据送往指定位置。
ALU:算数逻辑单元,可以进行移位逻辑运算和其它运算。
状态字缓存器:可以存放各种状态,比如说符号,条件码,进位,溢出等等,还可以存放运算控制信息。
分为三个阶段,取指->分析指令->执行指令
取指令的任务是:根据程序计数器PC中的值从程序存储器读出现行指令,送到指令寄存器。
分析指令阶段的任务是:将指令寄存器中的指令操作码取出后进行译码,分析其指令性质。如指令要求操作数,则寻找操作数地址。
计算机执行程序的过程实际上就是逐条指令地重复上述操作过程,直至遇到停机指令可循环等待指令。
一般计算机进行工作时,首先要通过外部设备把程序和数据通过输入接口电路和数据总线送入到存储器,然后逐条取出执行。但单片机
中的程序一般事先我们都已通过
写入器固化在片内或片外程序存储器中。因而一开机即可执行指令。
1.进制:一种计数方式,有限种数字符号来表示无限的数值,使用的数字符号的数目就是进位制的基数。
2.常见进制:二进制,八进制,十进制,十六进制等等。
3.进制之间的转换(相信大家耳熟能详,博主就不展开叙述了)
1.概述:在计算机当中,没有’+‘和’-'两种符号,它认识的是0和1,因此在计算机里面,使用0来表示正数,使用1来表示负数。符号位放最前面,其它为数值位。
2.原码表示法:符号位放第一位,其它为数值的二进制。原码表示法比较简单,但是在进行运算的时候非常复杂,特别是异号运算。因此比较少用它来计算。
3.反码表示法:原码除符号位以外,若为负数则其它数值位按位取反,若为正数则不变.可以通过反码找出其与补码之间的关系,从而方便计算补码。
4.补码表示法:对应原码的反码+1,便于运算。
1.定点数的表示:小数点固定在某个位置。其只有两种类型,一种是纯小数,小数点在符号位与数值位之间,一种是纯整数,小数点位于最后面。若遇到整数小数混合型的,则必须乘以相关比例把该数化成纯整数或者纯小数。
2.浮点数的表示:浮点数的表示范围比较大
格式:N=S*R^j 其中S指尾数,R指基数,j指阶码。
范围:若阶码取m位,尾数取n位,则阶码能够表示的最大值位2m-1,范围为[-2m+1,2m-1]。尾数的表示范围为:[2(-n),1-2(-n)]并上[2(-n)-1,-2^(-n)],
其中,如果出现了绝对值较小但是不在范围当中则称为下溢,如果绝对值较大并且不在范围当中则为上溢。
3.浮点数的规格化:
尾数必须为纯小数
尾数最高位必须为1
4.二者对比区别:
位数相同时,浮点数的表示范围比定点数大
浮点数的精度更加高
但是浮点数的运算更加复杂
5.定点数的加减运算: 数值位与符号位一同运算,进位则舍弃,得到补码以后,使用’+’,’-'符号来代替符号位,并且对数值位按位取反加一。
需要注意的是,溢出判断,我们一般采用的是双符号判断法,符号位由单符号改成双符号位,比如说0->00,1->11,运算过程当中,双符号位产生的进位丢弃,如果说双符号位不同,则产生溢出。
减法运算则需要把减号和对应数值转换成补码进行计算
6.浮点数的加减乘除运算:
操作流程:对阶(使浮点数的阶码一致)->尾数求和->尾数规格化->舍入->溢出判断
尾数规格化:需要判断尾数大于0和小于0的情况,规格化时,数值位最高位要与符号位不一致,如果不满足该情况,则左移,同时阶码发生相应的变化,如果左移使得发生溢出,则右移并且0舍1入。
乘法:阶码相加,尾数相乘
除法:阶码相减,尾数相除。
计算机原理是大学里面的核心课,也是CS专业的基础课,各大公司招聘面试时考核的重点,希望能够给大家带来收获!!!
大家如果由兴趣的化可以点击这里自我检测你的掌握水平
最后,欢迎大家关注我的个人博客,在下所有的文章都是从个人博客导入进来的,文章会首先更新在个人博客里。希望我的博客能够给大家带来收获!