计算机组成原理——计算机硬件组成与原理
计算机组成原理——计算机硬件组成与原理
计算机系统
计算机系统由硬件和软件来组成。软件分为系统软件和应用软件两种,系统软件如操作系统、数据库管理系统;而应用软件如QQ、微信之类的。
计算机组成原理主要探讨硬件部分。
计算机发展历史
计算机发展
第一台电子数字计算机诞生于1946年美国宾夕法尼亚大学,名字被叫做ENIAC。它使用电子管作为逻辑元件,总共有1.8万个电子管,因此体积大耗电量高速度还慢。在这一阶段程序员都是使用机器语言编程(面向过程的编程语言FORTRAN在第二代计算机时出现),需要将程序转为纸带上的打孔。
另外提一句,如果纸带上有一跳虫子,你的计算机程序就不可能正常运行,这也就是bug一词的来源。
发展阶段 | 时间 | 逻辑元件 | 速度(次/秒) | 内存 | 外存 |
---|---|---|---|---|---|
第一代 | 1946-1957 | 电子管 | 几千-几万 | 汞延迟线、磁鼓 | 穿孔卡带、纸带 |
第二代 | 1958-1964 | 晶体管 | 几万-几十万 | 磁芯存储器 | 磁带 |
第三代 | 1964-1971 | 中小规模集成电路 | 几十万-几百万 | 半导体存储器 | 磁带、磁盘 |
第四代 | 1972-现在 | 大规模、超大规模集成电路 | 上千万-万亿 | 半导体存储器 | 磁盘、磁带、光盘、半导体存储器 |
摩尔定律
摩尔定律:集成电路上可容纳晶体管数目约每18个月就会增加一倍,整体性能也将提升一倍。这个定律实际上是个经验总结,由Intel创始人戈登·摩尔提出,并没有严谨的推导,它在过去符合行业的发展,然而现在由于材料的物理极限已经失效了(截止到我写这篇文章的时候,芯片工艺已经发展到3nm,再小下去由于量子隧穿效应就很难再正常以栅压去控制器件的通断)。
软件的发展
最早程序员使用机器语言进行编程,后来诞生了汇编语言,但汇编语言编写起来仍然麻烦,于是人们发明了FORTRAN、PASCAL、C等高级语言。
发展趋势
计算机目前发展趋势两极分化,微型计算机朝着更微型化、网络化、高性能、多用途发展,如个人电脑、手机以及一些智能穿戴类设备;而另一极是巨型机朝向更巨型化、超高速、并行处理、智能化方向发展,如超级计算机。
计算机硬件基本组成
冯诺依曼结构
ENIAC的设计顾问叫冯·诺伊曼,他提出了存储程序的概念,即将指令以二进制代码的形式实现输入计算机的主存储器,然后按其存储器中的首地址执行第一条指令,以后就按该程序的规定顺序执行其他指令,直至程序执行结束。
- 输入设备负责将信息转换成机器能识别的形式
- 存储器负责存放数据和程序
- 运算器负责算数运算(加、减、乘、除)与逻辑运算(与、或、非)
- 控制器用一些电信号协调其他部件,以及检查读取存储器的指令
- 输出设备负责将数据输出为人们所理解的形式
在计算机中,软件和硬件在逻辑上是等效的。也就是说一个功能我们既可以用软件来实现,又可以用硬件来实现。用软件来实现的方式成本较低而且方便,但是速度相对较慢;用硬件实现的方式通常成本高昂但是速度快。
例如实现乘法运算,若计算机只提供了硬件上的加法功能,我们可以用软件实现乘法为依次累加,但是这样性能开销比较打;因此一些计算机就提供了乘法寄存器,用于在硬件上执行乘法运算,这种方式速度就快了不少。
冯诺依曼计算机有如下特点:
- 计算机由存储器、运算器、控制器、I/O设备组成。
- 指令和数据以同等地位存放于存储器,可按地址寻访。
- 指令与数据以二进制表示。(方便由电信号表示,例如高电平为1,低电平为0)
- 指令由操作码和地址码组成。操作码用于指明是什么操作,比如加法运算;而地址码指明我们操作的数据存放在存储器哪个位置。
- 存储程序。
- 以运算器为中心。
现代计算机结构
现代计算机结构实际上是传统冯诺依曼结构的扩展。传统的冯诺依曼结构由于输出设备从存储器中取走数据还需要靠运算器作为中转,这样做效率就会变得相对较低,因此现代计算机结构就以存储器为中心。
运算器与控制器通常被集成在同一个硬件上,统称为中央处理器,即CPU。IO设备经常被称为外设,而主存储器与CPU被称为主机。
存储器分为主存和辅存(外存),主存一般是我们平常所说的内存,它被归为主机的一部分,而辅存(如磁盘)被归为I/O设备。
硬件工作原理
主存储器
主存用于存放数据的部分叫存储体,此外还有两个部分,分别叫做存储地址寄存器(Memory Address Register, MAR)与存储数据寄存器(Memory Data Register, MDR)。
CPU想要获取数据,首先把地址写到MAR中,然后主存储器根据地址找到数据放到MDR中,CPU从MDR获取数据。
在存储体中,存在若干个存储单元,每个地址对应一个存储单元。
下面明确几个概念:
- 存储单元:每个存储单元存放一串二进制代码。
- 存储字(word):存储单元中二进制代码的组合。
- 存储字长:存储单元中二进制代码的位数。(通常是8bit或其正整数倍)
- 存储元:存储二进制的电子元件(如电容),每个存储元可存1bit。
若MAR有n位,则说明存储体有 2 n 2^n 2n个地址,也就是有 2 n 2^n 2n个存储单元。
若MDR有m位,则每个存储单元可以存放m bit,一个字的大小16bit。
运算器
运算器用于实现算数运算和逻辑运算。一个简单的运算器由累加器、乘商寄存器、通用寄存器、逻辑运算单元组成。
- ACC:累加器,用于存放操作数或者运算结果
- MQ:乘商寄存器,在乘法、除法运算时存放操作数或结果。
- X:通用寄存器,用于存放操作数。
- ALU:逻辑运算单元,通过内部复杂电路实现算数运算、逻辑运算。
控制器
控制器由控制单元、指令寄存器、程序计数器组成。
- CU:控制单元,分析指令并给出控制信号。
- IR:指令寄存器,存放当前执行指令。
- PC:程序计数器,存放下一跳指令,有自动加一的功能。
完成一条指令需分为三个阶段:
- 取指令——PC
- 分析指令——IR
- 执行指令——CU
其中取指令与分析指令统称为取指,执行指令称为执行。
计算机系统层次结构
层次结构
最底层是微程序机器M0,直接由硬件执行微指令。在它上方的是传统机器M1,使用机器语言的机器,执行二进制机器指令,如乘法指令。机器指令的通过拆分成若干个微指令来执行。往上是微操作系统机器M2,该层次向上提供广义指令(系统调用)。操作系统机器上方是汇编语言机器,用汇编程序翻译成机器语言程序。在操作系统机器之上的是高级语言机器,用编译程序翻译成汇编程序。
下层是上层的基础,上层是下层的扩展。
三种级别语言
像C/C++、Java等语言都是高级语言,它们通过编译程序(编译器)来翻译成汇编语言。汇编语言实际上是一些助记符,它与机器语言意义对应,通过汇编程序(汇编器)转换成机器语言也就是二进制代码。
当然还有些高级语言(比如Python、Javascript、Shell)并不是通过编译器来编译,而是通过解释器解释成一一对应的二进制代码。
总的来说,编译程序时将高级语言编写的源代码全部语句一次性翻译成机器语言,而后再执行机器语言程序;解释程序将一条语句翻译成对应于机器语言的语句,并立即执行,紧接着翻译下一句,每次执行都要翻译。
计算机性能指标
存储器性能指标
MAR的位数反映了存储单元的个数,MDR的位数反映了存储字长的大小。所以:
主存储器总容量 = 存储单元个数×存储字长(bit) = 存储单元个数 × 存储字长/8 (Byte)
我们假设MAR为32位,MDR为8位,总容量就是2的32次幂成8bit,也就是4GB。
CPU性能指标
CPU主频,也就是CPU内部数字脉冲信号震荡的频率,它等于时钟周期的倒数,单位为Hz。
f = 1 T c l o c k f = \frac{1}{T_{clock}} f=Tclock1
CPI(Clock Cycle Per Instruction),即执行一条指令所需周期数。不同的指令其CPI不同,甚至相同指令CPI也可能有变化。
我们记执行一条指令的时间为 t I n s t_{Ins} tIns,则与CPI还有CPU时钟周期的关系如下:
t I n s = C P I × T c l o c k = C P I f t_{Ins} = CPI \times T_{clock} = \frac{CPI}{f} tIns=CPI×Tclock=fCPI
我们来看一个例子,假设某CPU主频为1000Hz,某程序包含100条指令,平均看来指令的CPI=3,该程序在CPU上执行多久?
t I n s = 100 × 3 × 1 1000 = 0.3 s t_{Ins} = 100\times3\times \frac{1}{1000} = 0.3s tIns=100×3×10001=0.3s
另一个CPU常用的性能指标为IPS,全称Instructions Per Second,即每秒执行多少指令。
I P S = f C P I IPS = \frac{f}{CPI} IPS=CPIf
我们同样可以用每秒执行多少次浮点运算FLOPS来衡量CPU性能。
这里需要注意KFLOPS、MFLOPS、GFLOPS、TFLOPS相邻单位之间的换算都是 1 0 3 10^{3} 103,同样对于主频GHz与MHz之间的单位换算也是如此。
系统整体性能指标
数据通路带宽:数据总线一次所能并行传送信息的位数(各硬件通过数据总线传输数据)。
吞吐量:指系统在单位时间处理请求的数量。
相应时间:指从用户向计算机发送一个请求,到系统对该请求做出响应并获得它所需要的结果的等待时间。
通常包括CPU时间(运行一个程序所花费的时间)与等待时间(用于磁盘访问、存储器访问、I/O操作、OS开销等时间)。
我们可以使用基准程序也就是我们常说的跑分软件来测量计算机处理速度,以便于被测量的计算机性能可以与运行相同程序的其他计算机性能进行比较。基准程序通常是设定好的一段程序,这个程序里包含了各种各样的指令,根据运行这些指令的耗时来综合评分。
其他问题
问:主频高的CPU是否一定比主频低的CPU快?
答案:不一定。例如两个CPU,A的主频为2GHz,平均CPI为10;而另一个CPU主频1GHz,平均CPI为1。
则我们来看下A的平均执行一条指令所需时间(这里由于各个量的单位一致所以结果不给出单位):
t A = C P I A f A = 10 / 2 = 5 t_A = \frac{CPI_{A}}{f_A} = 10/2=5 tA=fACPIA=10/2=5
那么B所用到时间为:
t B = C P I B f B = 1 / 1 = 1 t_B = \frac{CPI_B}{f_B} = 1/1 = 1 tB=fBCPIB=1/1=1
由此可见A的时间反而更长一些,所以其他情况未确定的时候并非主频越高CPU越快。
问:此外是否平均CPI相同A就一定快?
答案:也是不一定。例如A在硬件支持乘法指令,而B不支持,对于B来讲就需要多次使用加法指令来完成。
问:基准程序执行得越快一定说明机器性能越好吗?
答案:不一定。尽管我们通常使用基准程序来测试机器性能,但是基准程序中的语句存在差异运行结果也不能完全说明问题。举一个生活的例子来讲,就是有些电脑跑分快,未必打游戏的性能就好(当然这个过程游戏厂商可能会对特定硬件做一些优化,我们忽略不计)。