第15章 精简指令集计算机

自从1950年前后开发存储程序计算机以来,计算机组成和体系结构领域几乎没有真正的创新,以下是重大进展:

1.系列的概念:系列的概念实现了计算机体系结构与其实现的解耦;

2.微程序控制单元:微程序简化了控制单元的设计与实现工作,并提供了对系列概念的支持;

3.高速缓存:1968年,ibm首次在商用中存储器层次结构中插入缓存;

4.流水线:在串行机器指令中引入并行性的一种方法;例如指令流水线和向量处理;

5.多处理器:包含不同的结构和目标;

6.精简指令集体系结构;

大多数risc体系结构的关键要素如下:

1.大量通用寄存器和使用编译器技术来优化寄存器的用法;

2.有限且简单的指令集;

3.强调优化指令流水线;

15.1 指令执行的特点

与计算机相关的最显著的进化形式之一是编程语言。随着硬件成本下降,软件的相对成本上升。系统生命周期的主要成本是软件,而不是硬件。

研究人员和业界对此的反应是开发更强大、更复杂的高级编程语言。这些高级语言的特点包括:

1)允许程序更精确地表示算法;

2)允许编译器处理算法表达中不重要的细节;

3)通常自然地支持结构化编程或面向对象设计的使用。

带来的问题是语义差异,即高级语言提供的操作与计算机体系结构中提供的操作。表现在:

1.执行效率低,机器程序过大和编译器复杂。其关键特性包括:大型指令集/数十种寻址模式以及在硬件中实现各种高级语言语句。这些复杂指令集目的是:

a.简化编译器编写者的工作;

b.提高执行效率,因为复杂操作序列可以在微码中实现;

c.为更复杂/精细的高级语言提供支持。

为理解Risc倡导者的思路,回忆指令执行的特点:

1.执行的操作:决定了处理器要执行的功能以及它与内存的交互;

2.使用的操作数:操作数的类型及其使用频率决定了存储它们的内存组织和访问它们的寻址模式;

3.执行序列:决定了控制和流水线结构;

15.1.1 操作

赋值语句占主导地位,条件循环语句也占多数,这表明指令集的顺序控制机制也很重要。

回答一个问题:给定一个已编译的机器语言程序,大部分机器语言的执行是由源码中那些语句导致的,以及这些指令的执行时间是多少?

15.1.2. 操作数

Patterson的研究表明,大多数的引用都是针对简单的标量变量,发现每条指令平均引用0.5个内存操作数和1.4个寄存器操作数。这些研究表明有助于快速访问操作数的体系结构的重要性,优化的主要候选是存储和访问局部标量的机制。

15.1.3 过程调用

高级语言中的过程调用和返回的重点,是过程处理时参数和变量的数量以及嵌套深度。

1.很少有很长且不间断的过程调用序列和相应的返回序列。

2.程序仍然被局限在一个相对较窄的过程调用深度窗口。

15.1.4 启示

尝试让指令集接近高级语言不是最有效的设计策略。而通过对典型高级语言中最耗时特性进行优化,高级语言可以获得最佳支持。归纳而得的3个要素:大体描述risc。

1.使用了大量的寄存器或者编译器来优化寄存器的用法,这是为了优化操作数的引用,因为高级语言中赋值语句比例高,可以减少引用内存来提高性能,只不过代价是更多的寄存器引用。

2.特别注意指令流水线的设计。由于条件分支和过程调用指令的比例很高,所以简单的指令流水线效率很低。这表现为预取的指令大部分未被执行。

3.提出由高性能原语组成的指令集。指令应该具有可预测的成本(用执行时间、代码量和不断增加的能耗来衡量),并与高性能实现保持一致。

15.2 使用大型寄存器文件

高级语言中都有大量的操作数访问,反映了变量对寄存器存储的重度依赖。

寄存器文件在物理上很小,与alu和控制单元在同一个芯片上,并且使用了比高速缓存和内存地址短得多的地址。所以需要一种策略来让访问频率最高的操作数保存到寄存器中,最小化寄存器--内存操作。

有两种基本方法:一种基于软件,另一种基于硬件。软件方法靠编译器最大化寄存器的使用。编译器尝试为那些在给定时间内使用最多的变量分配寄存器,这个方法需要复杂的程序分析算法。硬件方法则是使用更多的寄存器,以便让更多的变量在寄存器中保存的时间更长。

15.2.1 寄存器窗口

由于大多数操作数引用都是针对局部标量的,问题是局部的定义随着每一次过程调用和返回而变化,而这些操作又是经常发生的。在每次调用时,局部变量必须从寄存器保存到内存,这样寄存器就可以由被调用过程来重新使用。此外,还必须传递参数。返回时,必须恢复调用过程的变量(加载回寄存器),并且必须把结果传递回调用过程。

典型的构成只使用少量的传递参数和局部变量。其次,过程调用的深度在一个相对较窄的范围内变化。未来利用这些属性,就需要使用多个小型的寄存器组,每一个寄存器组都分配给不同的过程。过程调用会自动切换处理器以使用另一个固定大小的寄存器窗口,而不是把寄存器保存到内存。相邻过程的窗口相互重叠以传递参数。

窗口被分成3个固定大小的区域。参数寄存器保存的参数是有当前过程的父过程传递下来的,它还保存要向上传递的结果。本地寄存器用来保存局部变量,由编译器分配。暂存寄存器用于与相邻的下一级(被当前过程调用的过程)交换参数和结果。请记住,除了重叠之外,两个不同级别上的寄存器在物理上是不同。

为了处理任何可能的调用和返回模式,寄存器窗口的数量必须不受限制。因此,寄存器文件实际上的组织形式是重叠窗口的循环缓冲区。在调用下一个过程时,发现窗口满了,那么就不能在缓冲区当前状态下进行调用。此时,会发生中断,保存最开始的窗口。一个N个窗口的寄存器文件能容纳N-1个过程调用,N的值不需要太大。

15.2.2 全局变量

刚才描述的窗口模式在寄存器中存储局部标量变量提供了一种有效组织方式。但是,并未解决全局变量存储。有两种方法:第一是在高级语言中声明为全局,并由编译器分配内存的位置,所以引用这些变量的机器指令将使用内存引用操作数,实现很简单,但效率很低。第二种是在处理器中合并一组全局寄存器,这些寄存器数量固定,可以用于所有的过程。缺点是增加硬件负担,以适应分开的寄存器寻址。此外,链接器必须决定将那些全局变量分配给寄存器。

15.2.3 大型寄存器文件和高速缓存

被组织成窗口的寄存器文件充当了一个小型的快速缓冲区,用于保存使用最频繁的所有变量的子集。

大型寄存器文件

高速缓存

全部局部标量

最近使用的局部标量

单个变量

内存块

编译器分配的全局变量

最近使用过的全局变量

根据过程嵌套深度进行保存/恢复

根据高速缓存替换算法进行保存/恢复

寄存器寻址

内存寻址

一个周期内寻址和访问多个操作数

每个周期内寻址和访问一个操作数

寄存器文件在空间使用方面的效率比较低,因为并不是所有过程都需分配他们全部窗口空间。高速缓存还存在另一种低效:数据按块读入高速缓存。而寄存器仅保存了正在使用的那些变量。

当程序模块单独编译时,编译器就不能把全局值分配给寄存器,这个任务必须由链接器来执行。

寄存器文件在寻址开销上优于高速缓存。

15.3 基于编译器的寄存器优化

编译器的目标:在寄存器而不是在主存中保留尽可能多的计算操作数,以最大限度地减少加载和存储操作。采取方法如下:将每一个驻留在寄存器中的程序变量分配给一个符号寄存器或虚拟寄存器。然后编译器把无限数量的符号寄存器映射到固定数量的实际寄存器。不重叠使用的符号寄存器可以共享同一个实际寄存器。如果在程序的某个特定部分中,需要处理的变量多于实际寄存器的限制,那么就需要将某些量分配给内存位置。

优化任务的本质是确定在程序的任意给定点上,那些变量要分配寄存器。risc编译器中最常使用的技术就是图形着色。

在使用大型寄存器组和基于编译器的寄存器优化之间存在权衡。研究表明即使是简单的寄存器优化,使用的寄存器超过64个也不会有什么效果,而对于相当复杂的寄存器优化技术来说,当超过32个寄存器,性能只有微小的提升。对于少量16个寄存器,与分离结构相比,具有共享寄存器组织的机器执行更快。

15.4 精简指令集架构

15.4.1 为什么是cisc

指令集愈来愈复杂的两个主要原因是:一是希望简化编译器,二是提高性能。而它们的根本原因则是程序员转向高级语言,架构师想设计出能为高级语言提供更好支持的计算机。

简化编译器似乎是显而易见的,但事实并非如此。编译器编写人员的任务是构建一个编译器,为高级语言生成良好的机器指令序列。risc研究人员发现复杂机器指令常常很难被使用,因为编译器必须找到完全适合该构造的情况。对于复杂指令集,为了最小化代码量,减少指令执行数,以及增强流水线而对生成的代码进行优化的任务要难得多。

另一个被提到的主要任务是预期cisc将产生更小,更快的程序。程序更小会有两方面的好处

1.由于程序占用的内存更少,可以节省资源。在内存如此便宜的情况,这种潜在的优势不在具有吸引力。

2。更小的程序应该能提升性能。原因有三:

第一,指令更少意味着要取的指令字节就更少;

第二,在分页的环境下,更小的程序占据的页更少,减少缺页故障;

第三,高速缓存包含更多指令。

注意到cisc上的编译器倾向于更加简单的指令,所以复杂指令的间接性很少发挥作用。由于cisc上有更多的指令,所以需要更长的操作码,从而产生更长的指令。最后rsci倾向于强调寄存器引用而不是内存引用,前者需要的位数更少。

日益复杂的指令集的第二个驱动因素是指令执行会更快。但是由于使用更简单指令的倾向,情况可能并非如此。整个控制单元必须变得更加复杂,为程序控制存储器必须变得更大,以便适应更丰富的指令集。这两个因素都会增加简单指令的执行时间。

15.4.2 精简指令集架构的特点

risc特点;

1.每个时钟一条指令;机器时钟周期被定义为:从寄存器中取出两个操作数,执行一次alu操作,并把结果存到寄存器所需时间。

2.寄存器-寄存器操作;大多数操作应该是寄存器-寄存器,只有简单的加载和存储操作访问内存,这种设计特点简化了指令集,从而也简化控制单元。以及鼓励使用优化寄存器,以便频繁访问的操作数能留在高速缓存中。

3.简单的寻址模式;使用简单的寻址模式。几乎所有cisc指令都使用简单的寄存器寻址,可能还会包括偏移寻址和pc相对寻址,简化了指令集和控制单元。

4.简单的指令格式;一般只使用一种或几种格式。指令长度是固定的,并且对齐边界。字段位置,尤其是操作码也是固定的。优点在于字段固定,操作码译码和寄存器取操作数可以同时进行。简化的格式简化了控制单元。由于是按字长单元取,所以取指也简化了。对齐边界也意味着单条指令不会越过页边界。

这些特点确定了risc方法的潜在优势,首先可以开发更有效的优化编译器。编译器生成的大多数指令都是简单,risc认为指令流水线技术在精简指令集上用起来更为有效。risc处理器对中断的响应能力更强,因为中断检查是相当基本的操作之间进行的。

15.4.3 cisc和risc特性

当前,人们认识到1)risc设计可以从一些cisc特性中受益;2)cisc设计可以包含一些risc特性中受益。

经典risc表现:

1.指令长度固定,一般为4字节;

2.少量的数据寻址模式,一般不超过5种;

3.没有简洁寻址就需要一次访存来获得另一个内存操作数的地址;

4.没有把load/store操作和算术运算相结合;

5.每条指令的内存寻址操作数不超过1个;

6.不支持load/store操作的任意数据对齐;

7.指令中数据地址使用内存管理单元的最大数量;

8.整数寄存器说明符的位数不小于5。这意味着一次可以显示引用的整数寄存器数量至少是32个;

9.浮点寄存器说明符的位数不小于4,这意味着一次可以显示引用的浮点寄存器数量至少是16个;

前2项表明指令译码的复杂性。后5项表明流水线的难易程度,最后2项表明充分利用编译器的能力有关。

15.8 risc和cisc之争

多年来,计算机体系结构和组成的总体趋势一直都是增加处理器的复杂性:更多的指令、更多的寻址模式、更多的专用寄存器。risc运动于此相反。评估risc方法的优点可以分为2类:

1.定量:比较程序的大小和执行速度;

2.定性:研究诸如高级语言支持和vlsi最佳使用等问题;

近年来,rsci和cisc的争论很大程度上已经平息,这是因为技术的趋同,随着芯片密度和原始硬件速度的提升,risc系统变得更加复杂。于此同时,cisc为了提高性能,cisc设计的重点放在传统上risc相关的问题上,比如增加通用寄存器的数量,以及更加重视指令流水线的设计。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值