概述:这部分主要是学习控制器所支持的指令需要如何设计
一、指令格式
回顾一下没必要记,熟悉计算机操作指令步骤就行
一台计算机所有的指令集合构成指令系统,也称为指令集。常见的Intel X86架构,手机的ARM架构之间的应用不能互通。
认识指令系统,首先需要知道指令的格式和结构组成
后续的学习中操作码和地址码之间还会存在操作数、寻址方式、指令类型、预留位/拓展位等
⭐长期记忆⭐
<span style="background-color:#f8f8f8"><span style="color:#333333">指令字长:一条指令的总长度(可变)
机器字长:CPU进行一次整数运算所能处理的二进制数据的位数(通常和ALU直接相关)
存储字长:一个存储单元中的二进制代码位数(通常和MDR位数相同)
半字长指令、单字长指令、双字长指令 --指令长度是机器字长的多少倍
指令字长会影响指令所需时间。如:机器字长=存储字长=16bit,则取一条双指令字长需要两次访存</span></span>
操作码指示用户要干什么?地址码指示用户要对谁操作?
一条指令包含的地址码个数划分指令的类别:
-
零地址OP:给出操作码,不需要地址码,如空操作、停机、关中断等指令。对于堆栈计算机(通过零地址指令计算的原理:遇到操作数就进行压栈,遇到操作符就把栈顶的操作数取出进行运算后压回栈顶),两个操作数隐含放在栈顶和次栈顶,计算结果压回栈顶。这种情况并不是不需要操作数,而是操作数会隐含在某一个特定的位置。
-
一地址OP+A1:第一种情况,CPU会从A1所指向的主存地址中取出数据并执行OP操作,OP(A1)-->A1(如加一、减一、取反、求补等)完成一条指令需要3次访存:取指-->读A1-->写A1。第二种情况,两个操作数,其中一个会隐含在某个寄存器中(如ACC),(ACC)OP(A1)-->ACC完成一条指令需要2次访存:取指-->读A1。注意!A1类比指针,指向某个主存地址,(A1)表示A1指向的内容
-
二地址OP+A1(目的操作数)+A2(原操作数):常用于两个操作数A1,A2的算数逻辑运算,(A1)OP(A2)-->A1,完成一条指令需要4次访存:取指-->读A1-->读A2-->写A1
-
三地址OP+A1+A2+A3(结果):常用于两个操作数A1,A2的算数逻辑运算,类似于二地址,区别在于显示的指向A3地址,完成一条指令需要4次访存:取指-->读A1-->读A2-->写A3
-
四地址OP+A1+A2+A3(结果)+A4(下址):(A1)OP(A2)-->A3,A4=下一条将要执行的地址,完成一条指令需要4次访存:取指-->读A1-->读A2-->写A3,注意!正常情况下是取完指令后PC+1,指向下一条指令。当前四地址将PC的值修改为A4所指地址,可以实现指令跳转
地址码位数的影响:n位地址码直接寻址范围=2^n,指令总长固定不变,地址码数量越多,位数越少,寻址能力越差。
指令长度划分:定长指令字结构和变长指令字结构
指令操作码长度分类:定长操作码和可变长操作码
指令操作类型分类:
二、扩展操作码
定长指令字结构+可变长操作码-->扩展操作码指令格式
个人理解:定长指令字结构限制了指令字长只能有16位,地址码占了3*4位长,剩余的操作码只能固定2^4个位数范围,所以用1111作为扩展位使用,类似于进制的最高位,逢十进一。
根据前面是否是全1可以直接判断当前操作码指令是几地址指令。
注意点:对比哈夫曼树,不允许短码是长码的前缀,短操作码前面的代码(0000-1110≠1111)要小于长操作码;各指令的操作码一定不能重复。
通常情况下,对使用频率较高的指令,分配较短的操作码;使用频率较低的指令,分配较长的操作码,从而减少指令译码和分析的时间。
举例:设指令字长固定为16位,设计一套指令系统满足:
-
有15条三地址指令 共2^4=16种状态,留出16-15=1种作为扩展
-
有12条二地址指令 共1×2^4=16种状态,留出16-12=4种作为扩展
-
有62条一地址指令 共4×2^4=64种状态,留出64-62=2种作为扩展
-
有32条零地址指令 共2×2^4=32种状态
2^4一共有0-15,16条指令。所以三地址是0000-1110,二地址指令以1111开头,12条二地址指令剩余的四条指令分别是1100,1101,1110,1111,均是11XX开头所以A1地址要是1011(顶格11),同理62条一地址指令剩余111110,111111均是11111X开头所以A1、A2、A3取范围如图所示,进行位数填充。思想:除多少条指令以外的留出指令作为扩展位。
0000 - 1110 | A1 | A2 | A3 | |
---|---|---|---|---|
1111 XXXX XXXX XXXX | 1111 | 000 - 1011 | A1 | A2 |
1111 11XX XXXX XXXX | 1111 | 1100 - 1110 1111 | 0000 - 1111 0000 - 1101 | A1 |
1111 1111 111X XXXX | 1111 | 1111 | 1110 - 1111 | 0000 - 1111 |
指令扩展意义:CPU可以根据前面多少位都是1可以判断该指令是几地址指令。CPU先读出当前指令是一个16位的指令,先判断前四位是全1对应三地址指令+解析,再检测后两位是不是全1。。。 以下是优快云优秀博主啦啦右一给出的例题解答,感觉更易懂,链接放文末
设地址长度为n,上一层流出m种状态,下一层可扩展出m×2^n种状态。
定长操作码可以提高译码识别速度,但是位数受限.
扩展(不定长)操作码指令更丰富,但是增加了译码分析难度,
三、指令寻址
CPU可以进行顺序寻址和跳跃寻址两种方式。
正常情况下,指令的执行是按照PC(程序计数器)进行(PC)+1-->PC指明下一条指令的存放地址。
但是,如果不是按照标准的两个字节存储,按照字节编址单个就需要加2,如果采用变长指令字结构也不能顺序寻址。
顺序寻址:满足(PC)+"1"-->PC条件:该系统采用定长指令字结构 == 指令字长 == 存储字长=16bit=2B == 主存按字编址
<span style="background-color:#f8f8f8"><span style="color:#333333">这里的1理解为1个指令字长,实际加的值会因指令长度、编址方式而不同</span></span>
跳跃寻址:其实可以理解为把PC的值进行修改,跳跃到指向的地址。本质上程序执行始终依赖于PC寄存器存储的指令
注:每一条指令的执行都分为“取指令”、“执行指令”两个阶段
四、数据寻址
数据寻址:指令寻址后确定当前指令是几地址指令,分析识别后确定本条指令的地址码指向的真是地址。 一地址指令 操作码(OP)…… 1001…0111假设指令字长=机器字长=存储字长,操作数为3
立即寻址:形式地址A就是操作数本身,又称为立即数,一般采用补码形式。 #表示立即寻址特征。
一条指令的执行:取指令访存1次,执行指令访存0次,暂不考虑存结果,共访存1次 优点:指令执行阶段不访问主存,指令执行时间最短 缺点:A的位数限制了立即数的范围。
如A的位数为n,且立即数采用补码时,可表示的数据范围为−2^n-1~2!^n-1 − 1
直接寻址:指令字中的形式地址A就是操作数的真实地址EA,即EA=A。
一条指令的执行:取指令访存1次,执行指令访存1次,暂不考虑存结果,共访存2次 优点:简单,指令执行阶段仅访问一次主存,不需专门计算操作数的地址。 缺点:A的位数决定了该指令操作数的寻址范围。操作数的地址不易修改。
间接寻址:指令的地址字段给出的形式地址不是操作数的真正地址,而是操作数有效地址所在的存储单元的地址,也就是操作数地址的地址,即EA=(A)。
优点:可扩大寻址范围(有效地址EA的位数大于形式地址A的位数)。便于编制程序(用间接寻址可以方便地完成子程序返回)。 缺点:指令在执行阶段要多次访存(一次间址需两次访存,多次寻址需根据存储字的最高位确定几次访存)。
寄存器直接寻址:在指令字中直接给出操作数所在的寄存器编号,即EA =Ri,其操作数在由Ri所 指的寄存器内。
一条指令的执行:取指令访存1次,执行指令访存0次暂不考虑存结果,共访存1次 优点:指令在执行阶段不访问主存,只访问寄存器,指令字短且执行速度快,支持向量/矩阵运算。 缺点:寄存器价格昂贵,计算机中寄存器个数有限。
寄存器间接寻址:寄存器Ri中给出的不是一个操作数,而是操作数所在主存单元的地址, 即EA=(Ri)。
一条指令的执行:取指令访存1次,执行指令访存1次暂不考虑存结果,共访存2次 特点:与一般间接寻址相比速度更快,但指令的执行阶段需要访问主存(因为操作数在主存中)。
隐含寻址:不是明显地给出操作数的地址,而是在指令中隐含着操作数的地址。
优点:有利于缩短指令字长。 缺点:需增加存储操作数或隐含地址的硬件。
偏移寻址方式,区别在于偏移的“起点” 不一样 基址寻址:以程序的起始存放地址作为“起点”
!!!重点:BR是专门的基址寄存器(操作系统中的“重定位寄存器”),计算机中使用某个通用寄存器(指令指明)代替BR。程序如果从地址100开始,那操作系统只需要修改BR的对应十进制100(0000 0000 0110 0100)浮动标识程序进行的位数。其中BR是面向操作系统的,程序员是不能直接修改BR的值的,可以操作程序修改通用寄存器的值,但是一旦通用寄存器作为BR后就不能操作修改。 要用几个bit指明寄存器?根据通用寄存器的个数,eg:2^3=8,3个bit指明0-7个寄存器。
变址寻址:程序员自己决定从哪里作为“起点”,图示同上BR-->IX 变址寻址:有效地址EA等于指令字中的形式地址A与变址寄存器IX的内容相加之和, 即EA= (IX)+A,其中IX可为变址寄存器(专用),也可用通用寄存器作为变址寄存器。 注:变址寄存器是面向用户的,在程序执行过程中,变址寄存器的内容可由用户改变(IX作为偏移量)不断更改IX的值,形式地址A不变(作为基地址)。
相对寻址:以程序计数器PC所指地址作为“起点” 相对寻址:把程序计数器PC的内容加上指令格式中的形式地址A而形成操作数的有效地址, 即EA=(PC)+A,其中A是相对于PC所指地址的位移量,可正可负(可以往前往后偏移),补码表示。
优点:操作数的地址不是固定的,它随着PC值的变化而变化,并且与指令地址之间总是相差一个定值,因此便于程序浮动(一段代码在程序内部的浮动)。相对寻址广泛应用于转移指令。 思想:在程序内浮动时不改变指令,改变循环体的位置例如+4再-4回到原始的位置 拓展:ACC加法指令的地址码,可采用“分段”方式解决,即程序段、数据段分。而IX比较则是程序通过cmp指令,实际上是a-b,想减的结果会记录在程序状态字寄存器PSW中。
<span style="background-color:#f8f8f8"><span style="color:#333333">PSW中有几个比特位记录上次运算的结果
• 进位/借位标志CF:最高位有进位/借位时CF=1
• 零标志ZF:运算结果为0则ZF=1,否则ZF=0
• 符号标志SF:运算结果为负,SF=1,否则为0
• 溢出标志OF:运算结果有溢出OF=1否则为0</span></span>
堆栈寻址:操作数存放在堆栈中,隐含使用堆栈指针(SP)作为操作数地址。 在寄存器中开辟堆栈成为硬堆栈,在内存中的是软堆栈。
寻址方式 | 有效地址 | 访存次数(指令执行期间) |
---|---|---|
立即寻址 | A即时操作数 | 0 |
直接寻址 | EA=A | 1 |
一次间接寻址 | EA=(A) | 2 |
寄存器(直接)寻址 | EA=Ri | 0 |
寄存器间接一次寻址 | EA=(Ri) | 1 |
隐含寻址 | 程序指定 | 0 |
转移指令 相对寻址 | EA=(PC)+A | 1 |
多道程序 基址寻址 | EA=(BR)+A | 1 |
循环程序 变址寻址 数组问题 | EA=(IX)+A | 1 |
堆栈寻址 | 入栈/出栈时EA的确定方式不同 | 硬堆栈不访存,软堆栈访存1次 |
五、CISC和RISC(指令设计方向)
参考博客:啦啦右一
参考课件:王道考研-408计算机组成原理