Java架构师成长之道之计算机组成原理组成篇
2.1 计算机总线
2.1.1 总线概述
以通用串行总线USB(Universial Serial Bus)为例子来理解什么是总线,
首先它提供了对外的连接接口,不同的设备(鼠标、键盘、U盘、移动硬盘)通过这个接口都可以进行连接,USB也成为了连接标准,促使外围设备接口的统一。除此以外还有PCI总线,Thunderbolt总线等等,总线是为了解决不同设备之间的通讯问题。2.1.2 总线分类
总线分为片内总线和系统总线两类。
- 片内总线 片内总线是芯片内部的总线,以CPU为例,总线连接高速缓存,控制器,中断系统,运算器。 片内总线可以连接寄存器与寄存器,寄存器与控制器、运算器之间的设备。 片内总线就是高集成度芯片内部的信息传输线,用来简化芯片结构。
- 系统总线 系统总线用于连接计算机外围设备,可以分为如下三类:
- 数据总线 数据总线位数和CPU的位数相同(32位,64位 ),用于双向传输各个部件的数据信息。
- 地址总线 如果地址总线位数为n,那么寻址的范围是0-2n次方,地址总线的位数和存储单元有关
- 控制总线 控制总线主要是用于发出各种控制信号的传输线,控制信号经过控制总线从一个组件发给另外一个组件,控制总线可以监事不同组件的状态(就绪/未就绪)
2.1.3 总线仲裁
总线仲裁主要是解决了不同组件使用总线的优先级。
常用的总线总裁的方法有如下三种:- 链式查询 设备之间通过电路串联,电路复杂低,仲裁方式简单,但是优先级低的设备难以获取总线的使用权,设备的优先级就体现在链式查询的先后顺序。
- 计时器定时查询 仲裁控制器对设备进行编号并使用计数器累计计数,接到仲裁信号以后,往所有设备发出计数值。计数值与设备编号一致则获得总线使用权。
- 独立请求 每个设备均有总线独立连接仲裁控制器,设备可单独向仲裁器发送请求和接受请求,当同时收到多个信号,仲裁器有权按照优先级分配使用权。
2.2 计算机的输入输出设备
2.2.1 常见的输入输出设备
常见的输入设备分为字符输入设备和图像输入设备。
-
字符输入设备
最常见的字符输入设备是键盘,键盘可以分为薄膜键盘、机械键盘按照不同的段落感、声音、压力和键程序分为黑轴、红轴、青轴、茶轴四种和电容键盘。 -
图形输入设备
最常见的图形输入设备有鼠标、扫描仪。 -
图像输出设备
最常见的图形输出设备有液晶显示器,打印机以及投影仪。
2.2.2 输入输出接口的通用设计
输入输出接口的通用设计主要有以下几点
-
数据线:是IO设备与主机之间的信息交换传输线,按照用途不同分为单向传输线和双向传输线。
-
状态线:IO设备状态向主机报告的信号线,主机可以通过状态线查询设备是否已经正常连接并就绪,同时还可以查询是否已经被别的设备占用。
-
命令线: CPU向设备发送命令的信号线,例如读写信号、启动、停止信号。
-
设备选择线:主机选择与IO设备进行操作的信号线,对连接在总线上的设备进行选择。
2.2.3 CPU与IO设备的通讯方法
CPU与IO设备的通讯方法主要有程序中断的方法以及DMA(直接存储器访问)两种
- 程序中断 当外围IO设备准备就绪,向CPU发出中断信号,CPU有专门的电路响应中断信号,当CPU收到中断信号,就会暂停当前的任务,转而处理IO设备的工作,当处理完成后再处理当前的任务。
程序中断提供低速设备通知CPU的一种异步方式,CPU可以高速运算的同时兼顾低速设备的响应,但是CPU速度与IO设备速度不匹配,所以会降低CPU的效率。
- DMA(直接存储访问) DMA直接连接主存和IO设备,DMA工作时不需要CPU的参与。 当主存与IO设备交换信息时,不需要中断CPU,可以大大提高CPU效率。 在硬盘、显卡中都有DMA的存在。
2.3 计算机的存储器
2.3.1存储器的分类
存储器的分类按照存储介质可以分为半导体存储器和磁存储器
常见的半导体存储器有内存、固态硬盘。 常见的磁存储器有磁盘。存储器按照存取方式分类可以分为如下三种:
随机存储器(RAM),可以随机读写,存储的时间和位置没有关系。 串行存储器,存储的时间和位置有关系, 只读存储器(ROM),只读不写,例如手机的固件,电脑的BIOS。2.3.2 存储器的层次结构
在选配磁盘时考虑的通常是读写速度以及磁盘的容量和价格三大因素,而存储器的层次结构可以分为缓存、主存和辅存。
缓存是CPU的寄存器和高速缓存,容量最低,速度最快,价格最高 主存就是计算机的内存,容量适中,速度适中,价格适中 辅存就是计算机的外部存储设备,例如磁盘、移动硬盘等。 容量最高,速度最慢,价格低在计算机存储结构中,CPU可以和高速缓存、主存直接进行通讯,高速缓存和主存可以直接进行通讯,这种层次结构被称为缓存-主存层次,其实现方式就是在CPU和主存之间加一层速度快但是容量小的高速缓存, 用于解决CPU和主存速度不匹配的问题。
其实现原理就是局部原理:CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中,CPU将程序经常访问的内存数据加载到缓存中,然后直接访问缓存即可。
主存和辅存直接进行通讯,这种层次被称为主存-辅存层次,其实现就是在主存之外增加辅助存储器,其目的是解决主存容量不足的问题。
2.3.3 计算机的主存储器和辅助存储器
计算机的主存储器也被称为随机存储器(Random Access Memory)即内存,RAM通过电容存储数据,必须每隔一段时间刷新一次,如果掉电,那么一段时间后将丢失所有数据。
内存由半导体存储体、驱动器、译码器、读写电路和控制电路组成。
CPU通过内部的主存数据寄存器(mdr)通过数据总线访问读写电路,同时CPU的主存地址寄存器(MAR)通过地址总线指定数据的位置,然后通过数据总线传输数据。不同的操作系统对内存的支持是不一样的,目前最常用的操作系统分为32位和64位。
32位系统最大支持4GB内存。因此32位系统的地址总线只有32位数 而64位系统支持超过4GB的内存,例如笔记本的8GB-64GB,服务器通常是16GB-256GB。目前计算机中常用的辅助存储器有磁盘、移动硬盘。
2.3.4 计算机的高速缓存
计算机的高速缓存位于CPU和主存之间,其出现的目的是为了解决CPU与主存速度不匹配,提高CPU效率。
2.3.4.1 高速缓存的工作原理
为了了解高速缓存的工作原理,首先需要了解主存的相关概念:字和字块
字:存放在一个存储单元的二进制代码组合,一个字可以表示数据、指令或者字符串 字块:存储在连续的存储单元中而被看做一个单元的一组字,即字块包含了多个字。假设一个字有32bits,一个字块共有B个字,主存共有M个字块。
那么主存总字数=BM,而主存总容量=BM*32bits而字的地址包含两个部分,前m位表示字块在内存中的地址,后b位指定字在当前字块的地址。因此2m=M(总字块),2b=B(总字数)。
假设主存的用户空间为4G,字块大小为4M,字长位32位,则对于字地址中的块地址m和块内地址b的位数,至少应该是多少?
首先求出字块数:4G/4M=4*1024M/4=1024
字块地址m: log2(1024)=10log2(1024)属于对数运算,其计算结果可以使用Windows10自带的计算器获取,
首先切换至科学型,默认是标准型,然后分别输入1024、log、/、2、log、=即可以求出结果块内字数:4M/32bit=1048576
块内地址:log2(1048576)=20log2(1048576)也是属于对数运算,其计算结果可以使用Windows10自带的计算器实现获取,
首先切换至科学型,默认是标准型,然后输入1048576、log、/、2、log、=即可以求出结果根据计算结果m≥10,b≥20得知字地址的块地址至少是10位,字地址的块内地址至少是20位。
高速缓存和主存的存储逻辑结构类似,缓存相对于主存容量较小,速度更快等特点。
CPU访问高速缓存的两种情况
- CPU需要的数据在缓存中
- CPU需要的数据不在缓存中需要从主存中拿,然后复制到高速缓存中
命中率和访问效率是衡量缓存的重要性能指标
理论上CPU每次都能从高速缓存中获取数据的时候,命中率为1,但是由于高速缓存的容量远远小于主存的容量,因此命中率不可能为1。
命中率(h)计算的公式: 访问高速缓存的次数占总次数的比例
访问主存的次数:Nm 访问Cache的次数Nch=Nc/(Nc+Nm)
访问效率:e
访问主存的时间:tm
访问缓存的时间为tc 访问Cahe-主存 系统平均时间:ta=h*tc+(1-h)*tme=tc/ta=tc/h*tc+(1-h)*tm
缓存的命中率和访问效率例子:
假设CPU在执行某段程序时,共访问了Cache命中2000次,访问主存50次,已知Cache的存取时间为50ns,主存的存取时间为200ns,求Cache-主存系统的命中率、访问效率以及平均访问时间。命中率计算公式:
h=Nc/(Nc+Nm) h=2000/(2000+50)≈0.97 即缓存的命中率为97%访问效率计算公式:
e=tc/ta=tc/htc+(1-h)tme=tc/ta=tc/htc+(1-h)tm=50/(0.97*50+(1-0.97)200)=50/(48.5+0.03200)=50/54.5≈0.917
CPU访问存储系统的平均访问时间
ta=0.97*50+(1-0.97)200)=48.5+0.03200=54.5ns2.3.4.2 高速缓存的替换策略
在CPU执行程序时,为了提高执行效率,应该尽量从高速缓存中获取数据,也就是提高缓存的命中率和访问效率,此时需要良好的替换策略,高速缓存的替换时机是CPU需要的数据不在高速缓存中,此时需要从主存中获取数据,此时按照相关的策略替换高速缓存的数据,常用的高速缓存替换策略有如下几种策略。
- 随机算法 随机算法是每次需要替换缓存中的数据时随机选取高速缓存的数据替换掉。
- 先进先出算法(FIFO) 先进先出算法把高速缓存看做一个先进先出的队列,如果需要替换高速缓存的数据,优先替换最先进入队列的字块。
假设缓存一共可以缓存1-8一共8个字块,CPU运行程序时某次任务触发了缓存替换,需要将第9个字块存储到高速缓存中,此时根据FIFO的特性,第一个字块的数据将会从高速缓存中移除,然后将第九个字块放到高速缓存中。
-
最不经常使用法(LFU)
LFU优先淘汰掉最不经常使用的字块,因此需要额外的空间记录字快的使用频率,假设在某个时刻触发替换的行为,此时会将命中频率最低的字块替换掉。 -
最近最少使用算法(LRU)
LRU优先淘汰一段时间内没有使用的字块,有多种实现方法,通常使用双向链表实现,把当前访问的字块节点至于链表的前面,保证链表头部的字块是最近使用的,当需要淘汰的时候将链表尾部的字块淘汰掉。
2.4 计算机的指令系统
2.4.1 机器指令的形式
机器指令由操作码和地址码两部分组成。
其中操作码指明了指令所要完成的操作,操作码的位数反映了机器的操作种类,例如操作码有8位,即有2^8=256种操作。
地址码是给出操作数或者操作数的地址,因为机器指令本质上是操作数据,CPU根据数据或者数据的地址进行相应的运算,地址码分为三地址指令、二地址指令和一地址指令。三地址指令的机器指令包含操作码(OP),地址1(addr1),地址2(addr2),地址3(addr3),三地址指令通常会完成(addr1)OP(addr2)->(addr3),以操作码为加法为例子,将add1和add2对应的值相加,然后将相加的结果存放在addr3中。
二地址指令的机器指令包含操作码(OP),地址1(addr1)和地址2(addr2),二地址指令通常会完成(addr1)OP(addr2)-->(addr1)或者->(addr2),即将addr1和addr2按照操作码进行相关的运算后将结果存储在addr1或者addr2中,二地址指令则可以理解为类似a=a+b这样的操作。不过这个只是从较为宏观的角度去理解指令了。在计算机内部,a=a+b可能会分成多个指令去执行,比如:先将变量从内存加载到通用数据寄存器,然后从通用数据寄存器移动到ALU的缓冲寄存器,然后再做运算,而这里的数据移动也可以理解为二地址指令(源地址->目的地址)。
一地址指令的机器指令(addr1)OP->(addr1)或者(addr1)OP(ACC)->(addr1),一地址指令最常用的操作就是自增运算,只有一个操作数。
除了有地址指令之外还有一种零地址指令,即在机器指令中无地址码,例如空操作、停机操作和中断返回操作等等。
2.4.2 机器指令的操作类型
机器指令的操作类型主要有数据传输类型,算术逻辑操作类型,控制指令类型三种。
-
数据传输包含寄存器之间、寄存器与存储单元以及存储单元(高速缓存、主存、辅存)之间传输,而数据读写、交换地址数据、清零、置一等操作都是数据传输类型。
-
算术逻辑操作包含 操作数之间的加减乘除运算,与或非等逻辑运算以及移位运算(左移(乘以2),右移(除2)操作。
-
控制指令包含等待指令、停机指令、空操作指令、中断指令等等。
2.4.3 机器指令的寻址方式
机器指令的寻址方式包含指令寻址和数据寻址两种方式
指令寻址包含顺序寻址和跳跃寻址
顺序寻址就是按照指令的顺序依次执行,而当遇到跳转指令时需要跳转寻址。数据寻址主要有立即寻址、直接寻址和间接寻址三种方式。
-
立即寻址:指令可以直接包含操作数,即无需要访问存储器,直接从指令获取操作数 例如指令 OP addr1 6,优点是速度非常快,但是地址码位数限制操作数的表示范围。
-
直接寻址:机器指令直接给出操作数在主存的地址,直接寻址寻找操作数简单,无需计算数据的地址,优点是速度较快,缺点是地址码的位数限制操作数的表示范围。
-
间接寻址:指令地址码给出的是操作数地址的地址,例如指令 R1(OP)(add2),add2是主存操作数地址的地址,因此需要访问一次或者多次主存来获取操作数。优点是操作数的寻址范围大,缺点是速度慢。
2.5 计算机的CPU
2.5.1 计算机的控制器
计算器控制器的作用是协调和控制计算机运行,计算机控制器包含如下几部分组成
-
程序计数器
程序计数器主要是用来存储下一条指令的地址,当程序运行时,CPU循环从程序计数器中获取指令,当指令被拿出时,程序计数器会指向下一条指令,程序计数器是提供给其他控制单元当前需要执行指令的地址。 -
时序发生器
时序发生器属于电器工程领域,用于发送时序脉冲,CPU依据不同的时序脉冲有节奏的进行工作。生活中学习各种乐器根据节拍器学习,而时序发生器就是类似于乐器的节拍器。 -
指令译码器
计算机指令由操作码和地址码组成,指令译码器会翻译操作码对应的操作以及控制传输地址码对应的数据。 -
寄存器
- 指令寄存器 指令寄存器主要用于从主存或者高速缓存存储计算机指令,当CPU需要执行相关指令时直接从指令寄存器中获取指令并执行。
- 主存地址寄存器 主存地址寄存器保存当前CPU正要访问的主存单元的地址,使用地址总线和主存进行通讯。
- 主存数据寄存器 主存数据寄存器保存当前CPU正要读写的主存数据,使用数据总线和主存进行通讯。
- 通用寄存器 用于暂时存放或传送数据指令,还可以保存算术逻辑单元(ALU)运算的中间结果,通用寄存器的容量比一般专用的寄存器大。
-
总线
用于控制器和其他组件通讯
2.5.2 计算机的运算器
计算机的运算器主要是用来进行数据的运算,由如下部分组成
-
数据缓冲器
数据缓冲器分为输入缓冲和输出缓冲,输入缓冲暂时存放外部设备输入的数据,输出缓存暂时存放送往外部设备的数据 -
算术逻辑单元:(ALU)
ALU可以完成算术运算、逻辑运算、位运算,至于ALU是如何运算,请听下回分解。 -
状态字寄存器
状态字寄存器用于存放运算的状态,例如条件码、进位、溢出、结果正负等等,同时可以存放运算的控制信息,例如调试程序时的调试跟踪标记位以及允许中断位等等。 -
通用寄存器
主要是用于暂时存放或传送数据或指令,同时可以保存ALU运算的中间结果,容量比一般专用寄存器大。 -
总线
用于运算器和其他组件通讯
2.6 计算机指令的执行指令过程
计算机指令执行主要包含取指令、分析指令、执行指令三个步骤,这三个步骤由高速缓存(缓存数据和指令)、运算器、控制器完成,而CPU内部的高速缓存、运算器和控制器和由片内总线连接,为了演示指令执行的过程,首先将指令执行过程中使用的相关的设备和测试数据罗列出来。
-
高速缓存
- 数据缓存:缓存地址和数据信息
- 地址缓存:缓存地址、操作码和地址码信息
数据缓存测试数据
地址 | 数据 |
---|---|
1 | 188 |
2 | 199 |
3 | 110 |
4 | 120 |
地址缓存测试数据
地址 | 操作码 | 地址码 |
---|---|---|
101 | MOV | R0,R1 |
102 | LAD | R1,6 |
103 | ADD | R1,R2 |
104 | ADD | R1,R3 |
105 | JMP | 102 |
运算器
- 数据缓冲器
- 算术逻辑单元(ALU)
- 状态字寄存器
- 通用寄存器
- R0(100)
- R1(10)
控制器
- 程序计数器
- 指令寄存器
- 指令译码器
- 时序发生器
这里以执行地址缓存测试数据为101的指令:将R0的值移动到R1中 为例,说明指令执行的过程
高速缓存缓存数据(数据、指令)->程序计数器存储指令地址->指令缓存 根据指令地址获取操作码、地址码->指令寄存器缓存操作码、地址码->指令译码器译码->程序计数器加1->运算器->寄存器->ALU->状态字寄存器->数据缓冲器。
CPU在执行程序时,首先将内存中的机器指令的数据以及指令缓存在CPU的高速缓存中,然后从高速缓存中获取指令执行。首先程序计数器将当前执行的指令地址为101缓存起来,但是程序计数器只知道指令的地址,而不知道指令具体的内容,程序计数器可以根据指令的地址通过总线访问高速缓存的指令缓存来获取指令地址为101的操作码(MOV)和地址码(RO,R1),再通过片内总线访问指令寄存器,将指令的操作码(MOV)和地址码(R0,R1)缓存起来,因为指令寄存器不知道指令的具体内容,同时还需要将指令发送到指令译码器,发送指令之后程序计数器要加1,此时程序计数器存储下一条执行的指令102,指令译码器拿到地址为101的指令负责译码(理解指令的具体内容:将R0寄存器的数据移动到R1寄存器中去)后发出控制信号,指令译码器通过片内总线进入运算器中,运算器获取控制信号后将R0加载到ALU中去进行相关的运算,再把R0的数据通过数据总线传输到数据缓冲器,数据缓冲器将R0的值覆盖到R1,此时R1的值就是100,此时高速缓存地址为101的指令完成。
-
取指令
CPU在执行程序时,首先将主存中的机器指令缓存在高速缓存中,然后从指令缓存中获取指令,并将指令送到指令寄存器。 -
分析指令
首先从指令寄存器取出指令传输到指令译码器进行译码操作,识别区分不同的指令类别和各种操作数据的方法。然后指令译码器发出控制信号,同时程序计数器加1,指向下一条指令。 -
执行指令
首先装载数据到寄存器,通过ALU处理数据,如果有进位、溢出会通过状态字寄存器记录运算状态,最后将运算结果返回。
2.4.4.2 CPU流水线设计
在指令的执行过程中取指令和和分析指令是由控制器完成的,而执行指令主要是由运算器完成的,也就是运算器和控制器不能同时工作,这样会导致CPU的综合利用效率不高,因此我们需要改进指令执行的过程来提高CPU的效率。
CPU的流水线设计类似于工厂的装配线,其特点是工厂的装配线使得多个产品可以被加工,在同一个时刻,不同的产品位于不同的加工阶段。
在未使用流水线设计之前,如果想要执行两条指令的流程如下
取指令->分析指令->执行指令->取指令->分析指令->执行指令 串行执行的。
在使用流水线设计之后,如果想要执行多条指令的流程如下
指令 | 时间片 | 时间片 | 时间片 | 时间片 | 时间片 | 时间片 | 时间片 | 时间片 | 时间片 |
---|---|---|---|---|---|---|---|---|---|
1 | 取指令 | 分析指令 | 执行指令 | ||||||
2 | 取指令 | 分析指令 | 执行指令 | ||||||
3 | 取指令 | 分析指令 | 执行指令 | ||||||
4 | 取指令 | 分析指令 | 执行指令 | ||||||
5 | 取指令 | 分析指令 | 执行指令 | ||||||
6 | 取指令 | 分析指令 | 执行指令 | ||||||
7 | 取指令 | 分析指令 |
由于每个时间片都有一条或者多条指令正在执行,CPU流水线设计的执行指令效率是串行执行效率的三倍左右,公式如下所示
串行执行m条指令: T1=3t*m
流水线执行m条指令: T2=t*(M+2)
效率计算方式如下所示:
H=T2/T1=t*(m+2)/3tm=1/3+1/(3m)