指令系统
字、字长
字:计算机中的基本访问单位
MIPS体系结构中,字长与寄存器大小相同,为32bit
字长:决定虚拟地址空间的最大大小,比如32位机器支持最大虚拟地址空间为232
Intel X86体系中,字表示16bit数据类型,32位称为双字,64位称为四字
指令的基本概念
一条指令的构成:操作码+地址码
- 操作码负责解释“做什么”
- 地址码负责解释“对谁动手”
一台计算机的所有指令的集合构成该机的指令系统,也称为指令集(x86、arm)
根据地址码数目的不同,可以将指令分为零地址指令、一地址指令、二地址指令等
零地址指令
- 不需要操作数,如空操作、停机、关中断等
- 堆栈计算机(基于后缀表达式运算),两个操作时隐含存放在栈顶和次栈顶,计算结果压回栈顶
一地址指令
- 只需要单操作数:加1,减1,取反,求补等
- 指令 OP(A1)→A1,完成一条指令需要三次访存:取指令→读A1→写A1
- 需要两个操作数,单其中一个操作数隐含在某个寄存器(如隐含在累加寄存器(ACC))中
- 指令(ACC)OP(ACC)→ACC
二、三…地址指令
指令字长
指令字长:一条指令的长度(可变),将直接影响取指令所需时间
半字长指令、单字长指令、双字长指令表示指令是机器字长的多少倍
操作类型
-
数据传送
- LOAD,将数据从存储器放入寄存器中
- STORE,将寄存器中的数据放入存储器中
-
算数逻辑操作
-
算数:加减乘除、增减1、求补、浮点运算、十进制运算
-
逻辑:与、或、非、异或、位操作、位测试、位清除、位求反
-
-
移位操作
- 算数移位、逻辑移位、循环移位
-
转移操作(将导致PC(指令计数器)改变)
- 无条件转移 JMP
- 条件转移 JZ:结果为0;JO:结果已出;JC:结果有进位
- 调用和返回 CALL和RET
- 陷阱和陷阱指令
- 循环指令
-
输入输出操作
扩展操作码
定长指令字结构:指令系统中所有指令的长度都相等
变长指令字结构:指令系统中各种指令长度不等
定长操作码:指令系统中所有指令的操作码长度相同
- 优点:可以简化硬件设计,提高指令译码和识别速度
- 缺点指令数量增加时会占用更多固定位,留给表示操作数地址的位数受限
可变长操作码:指令系统中各指令的操作码长度可变
- 优点:指令字长有限的前提下仍能保持比较丰富的指令种类
- 缺点:增加了指令译码和分析的难度,使控制器的设计复杂化
扩展操作码指令格式:定长指令字结构+可变长操作码
注意:
不允许短码是长码的前缀,即短操作码不能与长操作码的前面部分的代码相同
各指令的操作码一定不能重复
对于使用频率高的指令,分配较短的操作码(减少译码时间)
设地址长度为n,上一层留出m种状态,下一层可扩展出m*2n种状态
指令寻址
下一条欲执行的指令的地址,将始终由程序计数器PC给出,并且每次取完指令后,PC一定会自动+“1”,再执行指令
顺序寻址
例如:对于一个变长指令字结构,主存按字节编址,指令字长=存储字长
-
读入一个字,根据操作码判断这条指令的总字节数n,来修改PC的值(每次+n)
-
根据指令的类型,CPU可能还要进行多次访存,每次读入一个字
这个“1”应该理解为一个指令字长,需要根据指令长度、编址方式来判断
跳跃寻址
由转移指令指出跳转至的指令地址,类似于C语言的GOTO语句
数据寻址
确定本条指令的地址码指明的真实地址
在一条指令中,再包含寻址方式位(4位二进制),一般加在地址位前。
寻址方式
- 直接寻址:指令字的形式地址A就是操作数的真实地址EA
- 一条指令执行取指令访存1次,执行指令访存1次
- 执行阶段仅访问一次主存,不需专门计算操作数的地址
- 操作数的地址不易修改
- 间接寻址:指令的形式地址装入的是主存中装有真实地址单元的地址,即EA=(A).
- 一次间址需要3次访存
- 过程可以套娃n次,称为n次间址,那么访存次数就是n+2次,将导致指令执行效率变低
- 可以扩大寻址范围(EA位数大于A的位数),便于编程(方便子程序通过间址返回)
-
寄存器寻址:指令字中直接给出操作数所在的寄存器编号,即EA=R1。
- 访存1次,只有取指令访存
- 执行阶段不访存,访寄存器
- 指令字短(寄存器数目少)且执行速度快,支持向量/矩阵运算
-
寄存器间接寻址:类似于间接寻址,只是寄存器中存放的是操作数所在主存单元的地址,即EA=(Ri)
-
隐含寻址:在指令中隐含着操作数的地址(例如隐含在ACC中)。
- 有利于缩短指令字长
- 需要增加存储操作数,或隐含地址的硬件
-
立即寻址:形式地址A就是操作数本身,又称为立即数(在前用#标识),一般采用补码形式
- 访存一次,来源于取指,指令执行时间最短
- A的位数限制了立即数的范围
偏移寻址
- 基址寻址:以程序的起始存放地址作为“起点” EA=(BR)+A
- BR:基址寄存器,在有的计算机内部使用通用寄存器实现,在指令中声明使用哪个寄存器作为BR,位数根据寄存器数量n判断(log2(n))
- 便于程序“浮动”,方便实现多道程序并发运行
- 面向操作系统,由操作系统或管理程序确定
- 可扩大寻址范围(基址寄存器的位数大于形式地址A的位数)
- 变址寻址:程序员自己决定从哪里作为“起点” EA=(IX)+A
- 变址寄存器IX(Index Register)
- 与基址类似,区别在于IX的内容面向用户,可由用户改变
- 在处理数组时,可以将A设定为首地址,通过并不断改变IX的内容(偏移量)来得到任意数组元素的地址,适合编制循环程序
- 基址与变址复合寻址:
- 先基址后变址:EA = (IX)+((BR)+A)
- 相对寻址:以程序计数器PC所指地址作为“起点” EA=(PC)+A
- A是相对于PC所指地址(下一条指令地址)的偏移量,可正可负,补码表示
- 操作码地址不固定,随PC值变化
- 便于程序浮动(代码块在程序内部的浮动),广泛应用于转移指令
堆栈寻址
操作数存放在堆栈中,隐含使用堆栈指针(SP)作为操作数地址
堆栈是存储器(或专用寄存器组)按LIFO原则管理的存储区,堆栈指针就是一个存储该存储区被读/写单元的地址的寄存器
- 执行指令期间:硬堆栈不访存(专用寄存器实现),软堆栈(主存实现)访存一次
CISC与RISC
指令系统的两种设计方向
CISC: Complex Instruction Set Computer
- 一条指令完成一个复杂的基本功能
- 代表:x86架构,使用
- 典型程序的80%的语句仅使用处理机中20%的指令
- 采用“存储程序”的设计思想,由一个比较通用的电路配合存储部件完成一条指令
- 32个通用寄存器
RISC: Reduced Instruction Set Computer
-
一条指令完成一个基本“动作”,多条指令组合完成一个复杂的基本功能
-
普遍采用微程序控制器
-
代表:ARM架构
-
一条指令一个电路,大部分指令一个时钟周期内完成,电路设计相对简单,功耗低
-
16个通用寄存器
条件码/标志寄存器
ALU进行计算后,得到结果并根据结果向标志寄存器写入信息
- CF—进位/借位标志
- ZF—零标志
- SD—符号标志
- OF—溢出标志
CF
针对无符号数
- 加法,若产生进位时CF置为1,否则为0
- 减法,按被减数进行取反+1当作加法处理,但是不产生进位时CF置1,否则为0
- 比较大小:若a<b,则CF置为1,否则为0
ZF/SF/OF
ZF:最近操作得出结果为0,则ZF置为1,否则置0
SF:最近操作的得到的结果为负数,则SF置为1,否则SF置为0
OF:最近的操作导致补码溢出,有正溢出和负溢出两种情况,溢出为1,否则为0
程序员可见状态
这里的“程序员”,既可以是实际写汇编人,也可以是产生机器级代码的编译器
可见状态
- 通用寄存器:写汇编会用
- 条件码/标志寄存器
- PC程序计数器:用于相对寻址
不可见状态
- MAR
- MDR
- 指令寄存器IR