指令系统
指令集:CPU能执行的各种不同指令的集合
指令:计算机处理的最基本单位(操作码(执行指令的内容,表明这条指令是什么)+操作数(要操作的对象,指令需要对哪些数据进行处理))
指令的要素
- 操作码:指令将要完成的操作
- 源操作数引用:操作会涉及一个或多个源操作数,这是操作所需的输入
- 结果操作数引用:操作可能会产生一个结果
- 下一指令引用:告诉处理器这条指令执行完成后到哪儿去取下一条指令
指令表示
操作码:被缩写成助记符:ADD/SUB/LOAD(由存储器装入)/STOR(保存到存储器)
操作数:用符号表示,用寄存器编号或内存地址替换操作数
指令格式:
- | OP | A1 | A2 | A3 | A4 |:(A1) OP (A2) -> A3,A4为下一条将要执行的指令的地址
- | OP | A1 | A2 | A3 |:(A1) OP (A2) -> A3
- | OP | A1 | A2 |:(A1) OP (A2) -> A1
- | OP | A1 |:OP (A1) -> A 或 (ACC累加器) OP (A1) -> ACC
- | OP |
扩展操作码:
- 定长操作码:𝒏位操作码字段的指令系统最大能够表示𝟐𝒏条指令
- 可变长操作码(扩展操作码):不同地址数的指令具有不同长度的操作码
假如指令具有以下格式:
可以根据开头的操作码的内容区分操作码长度和n地址指令
- 15条三地址指令操作码:0000 ~ 1110(开头四位操作码在0000-1110之间)
- 15条二地址指令操作码:1111 0000 ~ 1111 1110(开头是三地址指令唯一剩下的一个四位数:1111,在此基础上后面多使用四位用来区分不同的二地址指令,同时这四位最大为1110)
- 15条一地址指令操作码:1111 1111 0000 ~ 1111 1111 1110(开头是二地址指令唯一剩下的八位数:1111 1111,然后后面四位同理,空出最后一种)
16条零地址指令操作码:剩余的
例题:假设指令字长为16位,操作数的地址码为6位,指令有零地址、一地
址、二地址3种格式。
1、设操作码固定,若零地址指令有M种,一地址指令有N种,则二地址指
令最多有几种?
方法:由于是定长操作码,可以算出总的指令操作码位数,然后算出指令的个数,减去零地址和一地址指令的数量即可。
- 操作码位数:16-6-6 = 4,操作码个数:16,二地址数量:16-M-N
2、采用扩展操作码技术,二地址指令最多有几种?
0000-1110(空出最后一种给其他一地址和零地址指令)
3、采用扩展操作码技术,若二地址指令有P条,零地址指令有Q条,则一
地址指令最多有几种?
- 可以通过解方程的方法解决,我们可以通过二地址数量算出一地址,再通过一地址算出零地址。
- 假设一地址数量为R,则:可以列出方程:,然后求解即可
操作码
- 差异:不同的计算机上操作码的数目变动是很大的
- 共性:所有计算机上都会存在相同的常用操作类型
操作码类型:
- 数据传送
- 算术运算
- 逻辑运算
- 输入/输出
- 控制转移:
1、分支/跳转指令:把将要执行的下一条指令的地址作为它的操作数之一
2、跳步指令:包含一个隐含地址,该隐含地址等于下一指令地址加上该指令长度之和
3、过程调用指令:涉及由目前位置转移到过程的调用指令和由过程返回到调用发生位置的返回指令(类似函数的进入和返回)
操作数
常见类型:
- 地址
- 数值
- 字符
- 逻辑数据
地址
每条指令需要有四个地址引用:2个源操作数,1个目的操作数(可以和源操作数相同),以及下一指令地址(可隐藏)
每条指令中的地址数量越少,会使得:指令的长度越短,不需要复杂CPU,但是指令条数增多,执行时间更长,程序也更长更复杂
数值
计算机存储的数值是受限的(数值幅值、浮点数精度)
数值数据的类型:
- 二进制整数或定点数
- 二进制浮点数
- 十进制数
字符
- ASCII:每个字符被表示成唯一的7位二进制串
- 扩展的二进制编码的十进制交换码(EBCDIC):8位编码
- 统一码(Unicode):16 位 / 32 位
逻辑数据
将一个n位单元看成是由n个1位项组成,每项有值0或1
大端序和小端序
- 大端序:数据的低位字节存放在内存的高位部分
- 小端序:数据的低位字节存放在内存的低位部分
假设有32位的十六进制值12345678,将它存储在可字节寻址的存储器地址184处
看着顺眼的就是大端序
端序不影响结构中数据项的次序
操作数引用
- 操作数的实际值
- 操作数的地址(寄存器或主存/虚拟内存)
记号
- A: 指令中地址字段的内容(指令中本身的信息)
- R: 指向寄存器的指令地址字段内容(指令中本身的关于寄存器地址的信息)
- EA: 被访问位置的实际(有效)地址(数据的地址)
- (X): 存储器位置 X 或寄存器 X 的内容(X指向的寄存器或空间)
寻址方式
- 立即寻址
- 直接寻址
- 间接寻址
- 寄存器寻址
- 寄存器间接寻址
- 偏移寻址
- 栈寻址
立即寻址
操作数实际值出现在指令中
操作数 = A
- 快,除了取指令之外,不需要额外的存储器访问
- 但是数的大小受限于地址字段的长度
直接寻址
地址字段含有操作数的有效地址
EA = A
- 只要求1次存储器访问,且无需为生成地址而专门计算
- 但是只有有限的地址空间
间接寻址
地址字段指示一个存储器字地址, 而此地址出保存有操作数的全长度地址
EA = (A)
- 扩大了地址空间
- 但是取操作数需要2次访问存储器
寄存器寻址
地址字段指示的是寄存器
EA = R
- 指令中仅需要一个较小的地址字段, 且不需要存储器访问
- 但是地址空间十分有限
寄存器间接寻址
地址字段指示寄存器
EA = ®
- 扩大了地址空间,比间接寻址少1次存储器访问
- 但是相对于寄存器寻址,需要多1次存储器访问
偏移寻址:相对寻址
隐含引用的寄存器是程序计数器(PC),此指令后续的下一条指令的地址加上地址字段的值产生有效地址
EA = (PC) + A
- 利用程序局部性原理,节省指令中地址的位数
偏移寻址:基址寄存器寻址
被引用的寄存器含有一个存储器地址,地址字段含有一个相对于那个地址的偏移量(通常是无符号整数表示)
EA = (B) + A
偏移寻址:变址寻址
指令地址字段引用一个主存地址,被引用的寄存器含有对于该地址的一个正的偏移量
EA = A + (IX)
为完成重复操作提供一种高效机制
扩展:结合间接寻址和变址寻址
- 前变址:EA = (A + (IX))通过变址寻址得到的数据本身是一个数据地址
- 后变址:EA = (A) + (IX)A不是数据地址本身,而是存放数据的地址的空间的地址
栈寻址
栈指针保存在寄存器中,对寄存器中栈位置的访问实际上是一种寄存器
间接寻址方式
与栈相关的是一个指针,它的值是栈顶地址
栈
栈的实现:
- 栈基(base):保存为栈保留的内存块底、部位置的地址
- 栈限(limit):保存为栈保留的内存块另一端的地址
- 栈指针(pointer):保存栈顶的地址
- 向上/向下增长:向着地址增大/减小的方向增长
栈的应用:表达式求值(使用后缀表示(逆波兰表示))
指令格式的设计原则
- 指令尽量短
- 有足够的操作码位数
- 操作码的编码必须有唯一的解释
- 指令长度是字节的整数倍
- 合理选择地址字段的个数
- 指令尽量规整
指令长度
应该等于存储器的传送长度(即数据总线宽度),或者这两个值其中之一是另一个的整数倍
位的分配
对于给定的指令长度,在操作码数目和寻址能力之间存在着权衡考虑
- 使用变长的操作码
- 使用寻址位的考虑因素
变长指令
- 易于提供大的操作码清单,寻址方式灵活
- 但是增加了CPU的复杂程度
指令集设计
设计的基本原则:
- 完备性/完整性:操作类型应当尽可能完备,但太复杂了也会给硬件实现增
- 加困难
- 兼容性:应当兼容以前的指令系统,为软件重复利用带来方便
- 均匀性:应当能对多种类型的数据进行处理
- 可扩充性:操作码要预留一定的编码空间
设计的基本问题:
- 操作指令表:应提供多少和什么样的操作,操作有多复杂
- 数据类型:对哪几种数据类型完成操作
- 指令格式:指令的位长度、地址数目、各个字段的大小等
- 寄存器:能被指令访问的寄存器数目以及它们的用途
- 寻址:寻址方式的种类以及有效地址的计算
- 下一条指令地址的确定:通常通过PC寄存器实