本文主要是介绍计算机组织结构 第一二章复习笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
第一章:计算机系统结构的基本概念
研究计算乘法我们是用乘法器还是用多个加法器实现,这是计算机组成研究的事情,而怎样用电路实现一个乘法器是计算机实现研究的事情;再比如,研究主存的编址方式,容量,访问这些是计算机组成研究的事物,但我们研究主存的逻辑电路怎样设计,微组件的组装,使用的材料这些是计算机实现的研究。
系统结构的层次
一个计算机系统是由软件和硬件组成的,我们划分为以下几层:微程序机器级别,传统机器语言级别,操作系统级别,汇编语言级别,高级应用语言级别,应用语言级别。(如下图)
第一层是微程序机器级别(微指令)就是为指令系统,这里是由固件和硬件完成的微指令解释,如果在微程序机器级别实现的话叫做仿真,可以定义出多种指令系统。
第二层是传统机器语言(机器指令),机器指令就是在这一层实现。但是不是所有的计算机都有第一层的,直接就是第二层,比如RISC结构就是采用这种实现方法,这样的好处是速度快,这里仍然是属于物理机的范畴,因为实现机器语言的解释需要到固件和硬件。
第三级就是操作系统级别(机器指令和系统调用),到了这里就是出现了操作系统,也就说出现了虚拟机,在这里仍然可以对物理机进行调用。这里的机器语言分为两个部分,一个是传统的机器指令,另一部分是操作系统级指令,传统的机器指令是用于解释下一层(汇编层)的指令的。而操作系统级指令是指:对于像读写文件,打开/关闭文件诸如此类的系统接口(系统调用)。
第四级是汇编语言级别(汇编指令),这里是介于机器语言和高级语言的一个缓冲区,不一定所有的高级语言都编译为汇编,有的直接就编译为机器语言。汇编指令会编译为第二层和第三层的机器语言来交给机器执行。
第五级是高级语言(自然语言),这里就是我们日常用的像C++,Python,Java之类的,假如我们是执行的时候(一行行执行)才转为机器语言和汇编语言的那叫:解释。假如我们是提前转化好的,那叫编译,解释的好处是占用的存储空间小,而编译的好处是速度快。
第六层是应用语言,就是我们常用的那些SQL语言了,专门用于解决某些问题而设立的。
这六个级别,高一级的会把自己的语言解释或者编译为比自己低级的语言执行。
虚拟机大部分是由软件实现的,物理机是一定由固件/硬件实现的,虚拟机的有些操作也可以由固件/硬件实现,最典型的例子就是智能手机上面的摄像头。
固件是有软件功能的硬件,比如我们把软件固化到ROM里面,固件肯定会比纯硬件实现慢,但是会更加灵活(毕竟像ROM是可以擦除修改的,但纯硬件造好了就改不得了)。
系统结构的分类
(1)对系统结构进行分类最常用的是Flynn分类法。
根据Flynn分类法,在系统结构里面大家使用的 ”通货“ 分为三类:【IS】指令流,【DS】数据流,【CS】控制流。控制流可以理解为是对部件的控制指令之类的。
而部件分为:【CU】控制部件,【PU】处理部件,【MM】存储部件。
根据数据流和指令流的关系分为四种,SISD,SIMD,MIMD,MISD。
区分的时候关注两件事:出现多个PU-MM组合那就是MD,出现多个CU-PU组合那就是MI。
冯诺依曼计算机是SISD的计算机。
(2)冯氏分类法
用系统的最大并行度对计算机进行分类。最大并行度:计算机系统在单位时间内能够处理的最大的二进制位数。用平面直角坐标系中的一个点代表一个计算机系统,其横坐标表示字宽(n位),纵坐标表示一次能同时处理的字数(m字)。m×n就表示了其最大并行度。
(3)Handler分类法
根据并行度和流水线对计算机进行分类。把计算机的硬件结构分成3个层次,程序控制部件(PCU)的个数k,算术逻辑部件(ALU)或处理部件(PE)的个数d,每个算术逻辑部件包含基本逻辑线路(ELC)的套数w。
用公式表示
t(系统型号)=(k,d,w)
进一步改进
t (系统型号)=(k×k’,d×d’,w×w’)
系统结构设计的定量原理
这里介绍的是我们日后研究系统设计的一些法则性的东西,我们关注的是定量计算。
经常性事件
做优化需要优先考虑经常发生的事情,比如说,溢出和不溢出,那不溢出肯定是经常发生的,所以我们尽量优化不溢出的情况,
Amdahl定律
把优化权重考虑进来是amdahl定律的核心。关注两个参数:【Fe】可改进比,【Se】加速比。
F e = 部 件 的 执 行 时 间 总 执 行 时 间 Fe=\frac{部件的执行时间}{总执行时间} Fe=总执行时间部件的执行时间
S e = 部 件 改 进 前 耗 时 部 件 改 进 后 耗 时 Se=\frac{部件改进前耗时}{部件改进后耗时} Se=部件改进后耗时部件改进前耗时
系统性能能提高的倍数:
S = T o l d T n e w = 1 ( 1 − F e ) + F e S e S=\frac{T_{old}}{T_{new}}=\frac{1}{(1-Fe)+\frac{Fe}{Se}} S=TnewTold=(1−Fe)+SeFe1
这里同时揭示了一个事实,当 S e → ∞ Se\rightarrow \infty Se→∞, S → 1 1 − F e S\rightarrow\frac{1}{1-Fe} S→1−Fe1,我们对部件改进的越多,得到的总体性能提升就会越小。
CPU性能公式
- IC:程序的指令数量
- CPI:每条指令需要的时钟周期数量
C P I = 程 序 耗 费 时 钟 周 期 数 I C CPI=\frac{程序耗费时钟周期数}{IC} CPI=IC程序耗费时钟周期数
C P U 时 间 = 程 序 耗 费 时 钟 周 期 数 ∗ 时 钟 周 期 CPU时间=程序耗费时钟周期数*时钟周期 CPU时间=程序耗费时钟周期数∗时钟周期
程序局部性原理
局部性分为时间局部性和空间局部性,时间局部性的意思是当前用到的信息,推理可能是之后也用到的;空间局部性的意思是用到了当前区域,推理那可能附近的区域也会用到。
系统结构设计的任务
构造新的计算机系统结构需要考虑设计的结构是面向专门领域还是面向通用处理的;考虑使用什么标准,所谓标准就是像I/O总线有PCI,VME,SCSI标准,浮点数标准有IEEE,DEC,IBM;考虑在不同级别使用软件还是硬件实现功能。
设计系统分为从上而下设计,从下而上设计,以及从中间设计,当前,前两种已经淘汰了,从上而下设计就是先设计应用领域语言,再逐层下来,这样设计的系统结构移植性和兼容性好,从下而上设计的速度快,目前折中采用从中间开始设计(操作系统为虚拟机边界)
系统结构性能测评标准
当前最常见的测评套件是SPEC程序(但是是基于UNIX的)。研究测评,我们从两个角度考虑,第一个,单个比赛的结果的评比方法,第二个,多个比赛结果一起评比方法。(就好比运动会单个比赛和班级总成绩)
先来看单个比赛的评比方法:
执行时间和吞吐率
执行时间好理解,不多解释,吞吐率是(完成任务的数量 / 所有任务的数量)。
- 时间角度标准:执行时间
- 空间角度标准:吞吐率
再来看整合多个比赛的评比方法:
调和平均,加权几何平均
调和平均的意思是把多个比赛结果的工作负担作为权重,计算权重和平均。
∑ ( w i R i ) n \frac{\sum(w_iR_i)}{n} n∑(wiRi)
几何平均的意思是把多个比赛结果的工作负担作为权重,计算权重积平均。
∏ ( w i R i ) n \sqrt[n]{\prod(w_iR_i)} n∏(wiRi)
其他概念补充
冯诺伊曼计算机
冯诺依曼计算机的特点:以运算器作为中心,SISD计算机,指令和数据同等地位,存储器按地址访问,指令有操作码和地址码,采用二进制运算。
模拟和仿真
模拟的意思在当前计算机是用软件方法模拟一个计算机的指令系统,用解释的方式实现,最常见的应用是虚拟机,这是指我们VMware,VirtualBox那种虚拟机,俗称 “沙盒” ,但速度很慢的。
仿真的意思是用当前计算机的微程序去解释另一台计算机的指令系统,这叫做仿真,我们之前做的那种Android x86系统就是仿真。
并行
并行的意思是在一段时间内完成多个任务。我们最开始研究是指令级并行,当多核计算机出现之后,大家开始研究线程并行,进程并行,任务并行,到现在的分布式计算,属于多机并行,多机群并行。
透明
意思是不可见的意思,当某种程序员设计的层次对更底部的层是不可见的时候,我们叫那些部件对于程序员透明。比如说:虚存器对于系统程序员不透明,对于应用程序员透明。说白了就是没有权限的意思。
系列机
由同一厂家生产的具有相同系统结构、但具有不同组成和实现的一系列不同型号的机器。
兼容机
由不同公司厂家生产的具有相同系统结构的计算机 。
第二章:计算机指令集结构
指令系统属于物理机和虚拟机的边界,在操作系统和机器语言的分界面。
导读目录:
- 指令系统结构的分类
- 寻址方式
- 指令系统的设计和优化
- 两种方向的指令系统发展
- MIPS指令系统简述
指令系统结构的分类
在CPU种存放操作数有三种存储单元:堆栈,累加器,通用寄存器。我们的指令无非就是围绕着操作数转的,所以分为堆栈指令系统,累加器指令系统,通用寄存器指令系统,但目前堆栈和累加器这两种指令系统已经被淘汰了,当前都是通用寄存器指令系统。
那么在通用寄存器指令系统中,也有细分为两种:RR(寄存器-寄存器),RM(寄存器-存储器)。而当前只有RR型成为主流,为什么我们需要尽量把操作数放在寄存器呢?
首先寄存器肯定比存储器要快,其次能够使用更少的地址位数就能访问到操作属,可以减少指令长度。我们之后所学习到的指令系统都是RR型的。
寻址方式
这是老生常谈的问题了,寻址方式的终极目标,是能够表达出: E A → D a t a EA\rightarrow Data EA→Data,EA是有效地址。怎样把EA表示出来,可能因为位数不够的问题,我们要套娃套娃地才能表示出来。下面列举几种,首先先商定一些符号的使用:Reg[…]表示寄存器里的内容,Mem[…]表示存储器的内容。
- 寄存器寻址:
add r1,r2
, R e g [ r 1 ] = R e g [ r 1 ] + R e g [ r 2 ] Reg[r1]=Reg[r1]+Reg[r2] Reg[r1]=Reg[r1]+Reg[r2] - 立即数寻址:
add r1,6
, R e g [ r 1 ] = R e g [ r 1 ] + 6 Reg[r1]=Reg[r1]+6 Reg[r1]=Reg[r1]+6 - 偏移寻址:
add r1,120[r2]
, R e g [ r 1 ] = R e g [ r 1 ] + M e m [ 120 + R e g [ r 2 ] ] Reg[r1]=Reg[r1]+Mem[120+Reg[r2]] Reg[r1]=Reg[r1]+Mem[120+Reg[r2]] - 寄存器间接寻址:
add r1,[r2]
, R e g [ r 1 ] = R e g [ r 1 ] + M e m [ R e g [ r 2 ] ] Reg[r1]=Reg[r1]+Mem[Reg[r2]] Reg[r1]=Reg[r1]+Mem[Reg[r2]] - 直接寻址:
add r1,(1000)
, R e g [ r 1 ] = R e g [ r 1 ] + M e m [ 1000 ] Reg[r1]=Reg[r1]+Mem[1000] Reg[r1]=Reg[r1]+Mem[1000] - 存储器间接寻址:
add r1,@[r2]
, R e g [ r 1 ] = R e g [ r 1 ] + M e m [ M e m [ R e g [ r 2 ] ] ] Reg[r1]=Reg[r1]+Mem[Mem[Reg[r2]]] Reg[r1]=Reg[r1]+Mem[Mem[Reg[r2]]]
在对编译器进行调查,发现:偏移寻址和立即数寻址是用的最频繁的。
在存储器里面,有:字节,半字,单字,双字,我们如何去兼容这些单位呢?在真实的存储的时候,我们选择下图的B方案,这是一个你到底是想浪费时间还是浪费空间的矛盾问题。(当然浪费空间更好啦)
指令系统的设计和优化
对指令系统设计的话,我们需要根据之前说的:以经常性事件为重点,我们会选择频率高的功能用硬件来实现,因为硬件速度快,但是灵活性差。对指令系统的要求是:完整,规整,正交,高效率,和兼容。完整的意思是指令系统能给基本的问题解法给答案,保证能用这些指令组合能完成更多任务;正交的意思是各个字段独立,兼容指的是能够新增新指令。对于指令系统的操作分类可以精简到以下几类:
控制指令的优化
控制指令是用来改变控制流的,分为四种:分支,跳转,调用,返回。所谓分支指的是条件跳转,返回必须有调用才有返回。根据数据调查,我们可以发现,分支的使用是最频繁的(如下图)。
思考实现分支指令,我们有几种方法,第一,我们可以用一个寄存器来存储比较结果,第二,利用ALC里面的一个位来表示,第三另外设置一个新的指令来判断。根据速度等因素的考虑,我们会使用第一种(用寄存器来存储比较结果,也就是我们在汇编使用的flag寄存器)
指令操作码的优化
这个我们最熟悉就是赫夫曼压缩法了。基本思想是我们用短的码表示发生频率高的事件,用长的码表示发生频率低的事件。我们需要构造赫夫曼树就能完成整个编码过程。
之外,我们还需要知道信息熵的计算,平均码长计算,信息冗余度计算。
- 信息熵的计算(最短平均码长):
H = − ∑ i n p i ∗ l o g 2 ( p i ) H=-\sum^n_{i}pi*log_2(pi) H=−i∑npi∗log2(pi) - 平均码长的计算:
L = ∑ i n p i ∗ l i L=\sum^n_ipi*li L=i∑npi∗li - 信息冗余度(无用信息的比例)的计算:
r = L − H L r=\frac{L-H}{L} r=LL−H
需要注意的是平均码长和最短平均码长不是一种东西!,信息熵的是用来表示某个信息能带来多少信息量,通俗说就是度量信息量的有多少计算。
考研需要牢记:赫夫曼树的构造,最短平均码长信息熵的计算,信息冗余度的计算,平均码长的计算的方法。
除了赫夫曼编码压缩法之外,还有等长拓展码的编码方式。这是模拟了数字进位的方法,我们有九个阿拉伯数字,但是数那么大,我们没有理由创造更多的数字,只能用位数来表达更多的信息。
比如说:3/3/3拓展码的编码法,我们每两个二进制位就要进位,那2/7编码法,在右边的位数可以最大
是7。
需要注意的是,把频率高的指令编码越短,这是无论哪种方法都要遵循的
下面是例子:
n1/n2/n3编码到底怎样编出来的呢?
以3/3/3为例
2/7编码:
15/15/15编码:
另外等长编码的到底多少位划分一个界限呢?这也是值得思考的问题
我们当然希望频率越高的码占据的位数越少,这是我们的目的。我们看上图的频率剧烈分割点在哪,不难看出在0.22和0.13频率之间出现了分界面,所以前两个我们划分2个,后面的7个大致相似,所以使用2/7编码。
看一个例子:
一个计算机系统采用32位单字长指令,地址码是12位,如果定义了250条二地址指令,那么还有多少条条单地址指令?
怎么理解,这里的地址码限定为12位,说的是一个地址码就12位,如果有2个地址,那就是24位了!
二地址共用掉24位作操作数地址,高位有8位作操作码。
共有 2 8 = 256 2^8=256 28=256种操作码状态,现在只用了250种,因此,还有6个可以供下一个扩展用,一地址码就意味着有中间12位可以做操作码,于是根据乘法原理: 6 ∗ 2 12 = 24 K 6∗2^{12}=24K 6∗212=24K。
思考这种问题,我们需要从多地址指令开始想起。
再看一个例子:
某处理机的指令系统要求:三地址指令4条,单地址指令255条,零地址指令16条,指令字长12位,每个地址码长3位,问此时能用拓展编码为操作码编码吗?假如单地址是254条呢?
解:
对于三地址指令的编码:
操作码有三位,能表示的操作状态数量是 2 3 = 8 2^3=8 23=8种,因为需要4条,所以剩下空余数4个。
对于单地址指令的编码:
操作码能有6位,根据乘法原则: 4 ∗ 2 6 = 256 4*2^6=256 4∗26=256条,也就说最多能表示256种状态,需要单地址指令255个,剩下一个数。
对于零地址指令的编码:
操作码有3位,能表示 2 3 = 8 2^3=8 23=8条,剩下的一个数根据乘法原则 1 ∗ 8 = 8 1*8=8 1∗8=8,所以不够编码零地址指令了。
但是,如果我们的单地址指令有254条,剩下多一个数(256-254=2)的话,就变成:
操作码有3位,能表示 2 3 = 8 2^3=8 23=8条,剩下多的一个数,根据乘法原则 2 ∗ 8 = 16 2*8=16 2∗8=16,就够用来对零地址指令编码了。
指令操作数的优化
考虑操作数,我们不妨想一下,我们怎样区分数据类型呢?有两种方法,第一是在操作码里面指出,第二是在存储的数据里面带一个Tag,第二种方法需要的空间和动态检测数据类型花费的资源太大了,所以我们都是用第一种方法,直接在操作码指出数据的类型。
两种方向的指令系统发展
CISC方向
这是朝着利用更多硬件实现更多的指令的方向,能实现的功能越多越好,那拓展的都是些什么指令呢?第一是算术拓展,像求根号,sin,cos,tan,求指数那些,第二是增强数据传输指令的功能,比如传双字和半字的优化,大量数据传送的优化等,第三是对循环语句的优化,根据测试程序的调查显示循环体有1-3条语句的情况占据70%,也就说循环体一般很短,设置专门的循环指令,比如Loop,第四是根据高级语言来优化,在高级语言里面有一些常用的,会直接变成机器指令,加快速度。
RISC方向
这是朝着越简洁越工整越好的方向发展的,CISC的方向最大的问题是芯片面积过大(因为需要实现的硬件功能需要太多了)
原则:
的指令,在此基础上补充一些最有用的指令;
➢ 采用简单而又统一的指令格式,并减少寻址方式; 指令字长都为32位或64位;
➢ 指令的执行在单个机器周期内完成; (采用流水线机制)
➢ 只有load和store指令才能访问存储器,其它指令 的操作都是在寄存器之间进行; (即采用load-store结构)
➢ 大多数指令都采用硬连逻辑来实现;
这篇关于计算机组织结构 第一二章复习笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!