计算机硬件只能识别和理解机器语言程序,用各种高级语言编写的源程序最后都要翻译(汇编,编译,解释)成指令形式表示的机器语言才能在计算机上运行。
一台计算机能执行的机器指令的集合称为该机的指令集或指令系统,指令是构成程序的基本元素。系统程序员感觉到的计算机的功能特性和概念性结构就是指令集体系结构(ISA)。
1.指令格式
2.操作类型
3.操作数类型
4.寻址方式
5.操作码编码
6.指令系统的风格
7.机器级的表示
指令地址码的个数
一条指令中必须或隐含的包括以下信息
(1). 操作码。
指定操作类型,如: 移位、加、减、乘、除、传送等。
(2). 源操作数及其地址。
指出一个或多个源操作数或其所在的地址,可以是存储单元的地址、寄存器编号、I/O端口,
也可以在指令中直接给出一个立即数
(3). 结果的地址。
结果存放的地址,可以是存储单元的地址、寄存器编号、I/O端。
(4). 下条指令的地址。
下条指令存放的存储单元的地址。
有了1-3条可以实现一条指令的自动执行、有了第4条,就可以周而复始的自动执行一条条指令。
通常,下一条指令的地址不需要在指令中明显给出,而是隐含在程序计数器(PC)中。
指令按顺序执行时:只要自动将PC的值加上指令的长度,就可以得到下一条指令的地址。
当遇到转移指令不按顺序执行时,需要在指令中给出转移到的目标地址。
综上所述,一条指令由一个操作码和几个地址码构成。根据指令显式给出的地址个数,指令可以分为三地址指令、二地址指令、单地址指令和零地址指令。
三地址指令:
三个地址分别作为双目运算中的两个操作数地址和结果的地址。
二地址指令:
两个地址分别作为双目运算中的两个操作数地址,并将其中一个地址作为结果的地址。
单地址指令:
如果是单目运算(如:取反、取负等)指令,则其地址即是操作数的地址也是结果数的地址。
如果是双目运算,则另一个操作数的地址和结果数的地址都默认放在累加器中。
零地址指令:
可能本身就无操作数,也无地址码,例如关机指令、空操作指令等。
指令格式设计原则
指令格式的选择应遵循如下几条原则。
(1). 指令尽量短。
每条指令的长度短,使得程序占用的存储空间小,降低空间的开销。
(2). 要有足够的操作码位数。
向后兼容是的指令的操作类型不断增加,因此必须预留足够的操作码位数。
(3). 操作码的编码必须是一个唯一的解释。
操作码最终需要送到指令译码器进行译码,因此,指令要么是一个唯一的合法的编码,
要么是不合法的序列。当译码器发现是不合法的操作码时,出现“非法指令”异常。
(4). 指令的长度应是字节的整数倍。
指令存放在内存中,而内存往往是按字节编址。因此指令的长度应是字节的整数倍,
便于指令的读取和指令地址的计算。
(5). 合理选择地址字段的个数。
地址字段个数涉及到指令的长度和指令的规整性问题,它是空间开销和时间开销权衡的结果。
(6). 指令应尽量规整。
指令的规整体现在很多方面,例如:指令长度是否固定、地址码格式是否一致、
操作码位数是否固定、指令字中各字段的划分位置是否一致等。规整的指令系统会大大简化硬件的实现。
指令系统设计是计算机系统结构设计的关键之一。如果指令系统太复杂,也会给硬件实现增加难度。因此,较复杂的功能可以通过伪指令实现。运算指令应能对多种类型的数据进行处理,包括三种整数(字节、字、双字)和两种浮点数(单精度浮点数和双精度浮点数)类型。操作码字段要预留一点的编码空间,以便需要时进行补充。
操作数类型
操作数是指令处理的对象,从高级语言程序所用数据类型来看,指令涉及的基本操作数类型应该包括以下几类。
(1). 指针或地址。
指针或存储单元地址通常用无符号整数来表示
(2). 数值数据。
数值数据主要包括带符号整数和浮点数。带符号整数用二进制补码来表示,浮点数大多用IEEE754标准表示。有些指令系统也提供十进制运算指令,一般用NBCD码(8421码)表示十进制数。
(3). 位、位串、字符和字符串。
位和位串数据一般用来表示一些标志、控制和状态等信息。
字符和字符串用来表示文本、流式文件和基本信息等。
(4). 逻辑(布尔)数据。
表示逻辑值。
例如,IA-32处理器提供的基本类型有字节、字(16)位、双字(32)位、四字(64)位。
对于整数,有16位、32位、64位三种补码表示的整数和18位压缩BCD码表示的十进制整数;
对于序数(即地址、指针等),有字节、字或双字长的无符号整数;对与浮点数,有用IEEE754表示的32位单精度、64为双精度和80位扩展精度三种。
寻址方式
指令给出操作数和操作数地址的方式成为寻址方式。地址字段长度直接影响指令长度,因而指令地址码要尽量端,但操作数的存放位置又必须灵活,存放空间也尽量大。
常见的寻址方式有以下几种:
(1). 立即寻址
在指令中直接给出操作数本身,这种操作数称为立即数。
(2). 直接寻址
指令中给出的地址码是操作数的有效地址,这种地址称为直接地址或绝对地址
(3). 间接寻址
指令中给出的地址码是存放操作数有效地址的存储单元地址,可以是一次间接寻址过程,
还可以是多次间接寻址。
(4). 寄存器直接寻址
指令中给出的是操作数所在的寄存器编号,操作数在寄存器中。
因为寄存器数量远小于主存的存储单元数,所以寄存器编号比存储器地址端,
因而寄存器寻址方式的指令较短,采用这种寻址方式的操作数比用访存,因而指令执行速度快。
(5). 寄存器间接寻址
指令中给出的地址码是一个寄存器编号,该寄存器编号存放的是操作数的有效地址,
寄存器间接寻址指令较短,因为只要给出一个寄存器编号而不必给出有效地址。
指令长度和寄存器寻址指令的指令长度差不多,但由于要访存,
所以寄存器间接寻址指令的执行时间比寄存器寻址指令的执行时间更长。
(6). 变址寻址
变址寻址方式主要用于对线性表之类的数组元素进行方便的访问。
采用变址寻址方式时,指令中的地址码字段A给出一个基准地址,
例如,数组的起始地址,而数组元素相对于基准地址的偏移量在指令中明显或
隐含的由变址寄存器I给出,这样,变址寄存器的内容实际上就相当于数组元素的下标,
每个数据元素的有效地址为基准地址加变址寄存器的内容,
即操作数的有效地址EA=(I)+A,其中I表示变址寄存器I的内容。
(7). 相对寻址
如果某指令的操作数的有效地址或转移目标地址位于该指令所在位置的前、后某个固定位置上,
则可用相对寻址方式获得操作主有效地址或转移目标地址。采用相对寻址方式时,
指令中的地址码字段A给出一个偏移量,基准地址隐含由
(8).基址寻址
基址寻址方式下,指令中的地址码字段A给出一个偏移量,
基准地址可以明显或隐含地由基址寄存器B给出,操作数有效地址EA=(B)+A。
与变址方式一样,若任意一个通用寄存器都可以作为基址寄存器,
则指令中必须明确的给出通用寄存器编号,并标明作为基址寄存器。
变址寻址、基址寻址和相对寻址三种寻址方式非常类似,都是将某个寄存器的内容与一个形式地址相加生成操作数的有效地址,通常把它们统称为偏移寻址。
操作类型
(1).算术和逻辑运算指令
这类指令有加(ADD)、减(SUB)、比较(CMP)、乘(MUL)、除(DIV)、与(AND)、
或(OR)、取反(NOT)、取负(NEG)、异或(XOR)、加1(INC)、减1(DEC)等,
为了方便多字长数据的运算,大多数机器还设置了带进位的加(ADC)和带借位的减(SBB)指令等。
在算术运算指令中,有的计算机还专门设置了十进制数的运算指令。
(2). 移位指令
有的机器默认一条指令只移一位,如果要移多位的话,需要多条移位指令;
有的机器可以在指令中规定移动的位数,这样的话,移动多为的功能可以用一条指令实现。
各种移位操作的含义如下:
算术左移:操作数的各位依次向左移,低位补零。有些机器将原操作数的最高位移入进位标志(CF)位,这样,
通过判断符号标志和进位标志是否相等就可以判断是否发生了溢出。
算术右移:操作数各位依次向右移,高位补符号。有些机器将最低位移入进位标志位。
逻辑左移:操作同算术左移,大多数机器一般不在专门设置此指令。
逻辑右移:各位依次右移,高位补零,有些机器将原操作数最低位移入进位标志位。
小循环左移: 最高位移入进位标志位,同时也移入最低位。
小循环右移: 最低位移入进位标志位,同时也移入最高位。
大循环左移:最高位移入进位标志位,而进位标志位移入最低位。
大循环右移: 最低位移入进位标志位,而进位标志位移入最高位。
(3).传送指令
传送指令通常有寄存器之间的传送(MOV),从内存单元读取数据到CPU寄存器(LOAD)、
从CPU寄存器写数据到内存单元(STORE)等。
(4).串指令
对字符串进行操作的指令。如串传送、串比较、检索、和传送转换等指令。
(5).顺序控制指令
用来控制程序执行的顺序。如有条件转移(BEANCH)、无条件转移(JMP)、跳步(SKIP)
、调用(CALL)、返回(RET)等指令。
顺序控制类指令的功能通过将转移目标指地址送到PC中来实现。
转移目标地址:可用直接寻址方式给出(又称**绝对转移**),或由相对寻址方式给出(又称**相对转**移)
。有的机器还可以用寄存器寻址方式或寄存器间接寻址方式给出转移目标地址。
无条件转移指令:在任何情况下都执行转移操作,而条件转移指令(或称分支指令)
仅仅在特定条件满足时才执行转移操作。CF为进位\借位标志,ZF为零标志。
跳步指令(SKIP)是转移的一种特例,它使PC再增加一个定值,这个定值一般是指令字所占用的存储单元数。
调用指令也称为转子指令,和转移指令的根本区别在于执行调用指令时必须保存下条指令的地址。
返回指令的功能是在被调用过程执行完毕时,将事先保存的返回地址送到PC,
这样处理器就能回到原来的低矮用过程继续执行。
(6).CPU控制指令
这类指令有停机、开中断、关中断、系统模式切换以及进入特殊处理程序等指令。
大多数机器将这类指令划分为特权指令(也称为管态指令),只能在内核代码执行时使用、
以防止因用户使用不当而对系统运行造成危害。
(7).输入输出指令
这类指令用于CPU与外部设备数据或传送控制命令及状态信息。大多数机器都设置了这类指令,
但是它们的寻址方式一般较少,常见的只有寄存器寻址、直接寻址和寄存器间接寻址等。
4.操作码编码
指令的操作码字段可以是固定长度,也可以是可变长度。选择定长操作码还是可变长操作码,是时间和空间之间的开销权衡问题。希望降低空间开销时,代码的长度更重要,应采用紧凑的变长操作码和变长指令字;希望降低时间开销以取得更好的性能时,应采用定长操作码和定长指令字。
(1).定长操作码编码
指令的操作码部分采用固定长度编码,这种方式译码方便,指令执行速度快,但有信息冗余。
(2).扩展操作码编码
扩展操作码编码方式将操作码的编码长度分成几种固定长度的格式。可以采用等长扩张法,如4-8-12、3-6-9
这种等长方式扩展,也可采用不等长扩展法。扩展编码方式的操作码长度不固定,是可变的。
这种编码方式被大多非规整型指令集采用。
5.标志信息的生成与使用
条件转移指令(也称分支指令)通常根据程序当前生成的标志信息进行转移。标志信息也称条件码(cc)或状态码
常用标志:
ZF:零标志
SF:符号标志
OF:溢出标志
CF:进位/借位标志
逻辑运算指令,通常只有零标志ZF才有意义。可以通过判断ZF=1来确定与、或、非等操作的结果是否为0
生成的标志位可有专门的条件码寄存器(或称状态寄存器、标志寄存器、程序状态字寄存器)来存放,也可由指定的通用寄存器来存放。
6 .指令系统设计风格
(1).按操作数位置指定类型风格分为4种
累加器型指令系统:
这种类型指令系统中,总是把其中一个操作数隐含在累加器中,指令执行的结果也总是送到累加器中。
这种指令系统的指令字短,但每次运算都要通过累加器,因而,在进行复杂表达式运算时,
程序中会多出许多移入/移出累加器的指令。从而使程序变长,影响程序执行的效率。
栈型指令系统:
java虚拟机采用的是栈型指令系统。栈采用后进先出、先进后出存取方式的特定的存储取。栈型指令系统中,
规定指令的操作数总是来自栈顶。
栈型指令系统中的指令都是零地址指令或一地址指令,因此指令字短。但是由于指令所用的操作数只能来自栈顶,
所以,在表达式编译时,生成的指令顺序以及操作数在栈中的排列都有严格的顺序规定,因而不灵活,带来指令条数
的增加。
通用寄存器型指令系统:
这种类型指令系统的特点是,使用通用寄存器而不是累加器来存放运算过程中所用的临时数据。
其指令的操作数可以是立即数(I),或者来自通用寄存器(R)、或者存储单元(S),
指令类型可以是RR型、RS型、SI型、SS型等。RR表示两个操作数都来自通用寄存器、RS型表示两个操作数分别来自通用寄存器、存储单元,SI表示两个操作数分别来自存储单元和立即数。
Load/Store型指令系统:
load/store型指令系统也使用通用寄存器而不是累加器来存放运算过程中所使用的临时数据。
因此,它也是一种通用寄存器型指令系统。同时,它有一个显著的特点。
就是只有取数指令和存数指令才可以访问存储器,运算类指令不能访存,
也就是说运算类指令只能是RR型或RI型。比较规整,
体现在每条指令的指令长度和指令执行时间等能够比较一致。
目前,通用寄存器指令系统占主导地位。其原因:①通用寄存器和处理器集成在一起,作为ALU的操作数来源,两者都可以靠的很近,因而,可缩短传输延迟;②寄存器位于存储器层次化结构的顶端,速度快且容易使用。寄存器个数不能太多,否则,成本高且会延长存取时间而使得时钟周期变长。当然寄存器个数也不能太少,否则编译器只能把许多变量分配到内存单元,每次都要去内存访问操作数,影响程序性能。
(2).按指令格式的复杂度来分,分别是CISC和RISC两种类型指令系统
CISC风格指令系统(复杂指令集计算机):
例如 VAX 11/780指令系统包含16种寻址方式、9种数据格式、303条指令。
而一条指令包含1~2个字节的操作码和下续N个操作数说明符,而一个操作数说明符的长度可达1~10个字节
称这类计算机为**复杂指令集计算机**(简称CISC)
主要特点:
① 指令系统复杂:指令多、寻址方式多、指令格式多
② 指令周期长: 绝大多数指令需要多个时钟周期才能完成
③ 指令周期差距大:各种指令都能访问存储器,使简单指令和复杂指令所用的时间周期数相差很大,
不利于指令流水线的实现。
④ 采用微程序控制:由于有些指令非常复杂,以至于无法用硬连线控制器来实现,而微程序控制器
用软件设计思想实现硬件,可以实现对复杂指令的控制
⑤ 难以进行编译优化:由于编译器可选指令序列增多,使得目标代码组合增多,从而增加了目标代码优化的难度。
复杂指令系统使得计算机的结构越来越复杂,不仅增加了研制周期和成本,而且难以保证其正确性,甚至降低了系统性能。
RISC风格指令系统 (精简指令集计算机)
RISC的着眼点不是简单的放在简化指令系统上,而是通过简化指令使计算机结构更加简单合理,
从而提高机器的性能
主要特点:
① 指令数目少:只包含使用频率高的简单指令。
② 指令格式规整:寻址方式少、指令格式少、指令长度一致
③ 采用Load/Store型指令设计风格
④ 采用流水线方式执行指令:规整的指令格式有利于采用流水线方式执行,除Load/Store指令外,其他指令都只需要一个或小于一个时钟周期就可完成,指令周期短。
⑤ 采用大量通用寄存器:编译器可将变量分配到寄存器中,以减少访存次数。
⑥ 采用硬连线控制器:指令少而规整使得控制器的实现变得简单,可以不用或少用微程序控制。
⑦ 采用优化的编译系统:指令数少有利于编译器的优化。