计算机组成原理(5)----指令系统(1):https://developer.aliyun.com/article/1511489
(3)寄存器寻址
在指令字中直接给出操作数所在的寄存器编号,即EA=Ri,其操作数在由Ri所指的寄存器内。
采用这一寻址方式,执行一条指令时,只需要1次访存,即取指令时,访存1次,执行指令时,只需要访问寄存器,而不需要访存。
优点:指令在执行阶段不访问主存,只访问寄存器,指令字短且执行速度快(CPU中寄存器数量较少,那么只需要使用较短的bit位,就可以表示所有寄存器的编号),支持向量/矩阵运算。
缺点:寄存器价格昂贵,计算机中寄存器个数有限,则寻址能力有限。
(4)寄存器间接寻址
寄存器Ri中给出的不是一个操作数,而是操作数所在主存单元的地址,即EA=(Ri)。
采用这种寻址方式,执行一条指令需要2次访存,取指令需要访存1次,执行指令也需要访存1次。
特点:与一般间接寻址相比速度更快(因为操作数的真实地址存放在寄存器中,而非主存中),但指令的执行阶段需要访问主存(因为操作数在主存中)。
(5)隐含寻址
不是明显地给出操作数的地址,而是在指令中隐含着操作数的地址。
例如,有些指令显式地给出的地址只是指明了其中一个操作数,而另一个操作数则隐含在ACC(累加寄存器)中,也就是这个操作数的地址没有在指令中显式指出。
优点:有利于缩短指令字长。
缺点:需增加存储操作数或隐含地址的硬件。
(6)立即寻址
对于立即寻址,形式地址A就是操作数本身,又称为立即数,一般采用补码形式。
#表示立即寻址特征
这里和直接寻址做区分,直接寻址的形式地址A表示的是操作数的地址,而立即寻址形式地址A就是操作数本身。
采用这种寻址方式,只需要进行1次访存,即取指令时访存1次,而我们需要的操作数直接包含在指令中,所以执行指令时不需要访存。
优点:指令执行阶段不访问主存,指令执行时间最短
缺点:A的位数限制了立即数的范围。如A的位数为n,且立即数采用补码时,可表示的数据范围为 ~
偏移寻址:
接下来讲解的是"相对寻址","基址寻址","变址寻址",这三种寻址方式都可以归为"偏移寻址",因为这三个寻址方式的区别在于偏移的"起点"不一样。
基址寻址:以程序的起始存放地址作为“起点”,再加上形式地址A作为偏移量
变址寻址:程序员自己决定从哪里作为“起点”,再加上形式地址A作为偏移量
相对寻址:以程序计数器PC所指地址作为“起点”,再加上形式地址A作为偏移量
(7)基址寻址
将CPU中基址寄存器(BR)的内容加上指令格式中的形式地址A(由算数逻辑单元(ALU)进行加法运算),而形成操作数的有效地址,即EA=(BR)+A。
注:在操作系统中的“重定位寄存器”就是“基址寄存器”
在有些计算机中,不会专门设置“基址寄存器”,而是会用通用寄存器,可以在指令中指明,要将哪个通用寄存器作为基址寄存器使用。
如下图所示,指令的“寻址特征”用来表明用基址寻址的寻址方式,同时还需要几位来指明要将哪个通用寄存器作为基址寄存器使用(要用几个bit位,就需要根据寄存器总数判断,假如通用寄存器有8个,则只需要3bit即可,2^3=8)。图中使用通用寄存器R0,那么就会将R0中的地址作为基地址送到加法器中,同时将形式地址A作为偏移量送到加法器中,ALU通过加法运算得到最终的操作数存放地址。
基址寻址的作用:
若某段程序的起始地址不为0,那么可以采用基址寻址,将程序的起始地址+形式地址(偏移量),得到操作数的地址。
所以基址寻址便于程序浮动,方便实现多道程序并发运行。
当某程序在程序中的位置发生改变,操作系统只需要修改BR这一寄存器的内容即可。让BR指向当前程序的起始地址,那么即使该程序浮动,也不需要更改。
注:程序运行前,CPU将BR的值修改为程序的起始地址(这一地址信息存放在操作系统PCB中)
基址寄存器是面向操作系统的,其内容由操作系统或管理程序确定。在程序执行过程中,基址寄存器的内容不变(作为基地址),形式地址可变(作为偏移量)。
普通程序员可以用汇编语言修改通用寄存器的内容,但若某一通用寄存器被指定为基址寄存器,可由用户决定哪个寄存器作为基址寄存器,但其内容仍由操作系统确定。
优点:可扩大寻址范围(基址寄存器的位数大于形式地址A的位数);用户不必考虑自己的程序存于主存的哪一空间区域,故有利于多道程序设计,以及可用于编制浮动程序(整个程序在内存里边的浮动)
对于某条指令,形式地址A可能较短,寻址能力有限,但是在加上较长的基址地址,那么这一条指令可以访问的地址范围就能扩大。
(8)变址寻址
有效地址 EA 等于指令字中的形式地址A与变址寄存器IX的内容相加之和,即EA=(IX)+A,其中IX可为变址寄存器(专用),也可用通用寄存器作为变址寄存器
下图所示,左图为变址寻址,右图为基址寻址,除了寄存器不同,还有什么区别?
变址寄存器是面向用户的,在程序执行过程中,变址寄存器的内容可由用户改变(IX作为偏移量),形式地址A不变(作为基地址)
而在基址寻址中,BR保持不变作为基地址,A作为偏移量
变址寻址的作用:
如图所示,对于循环类的程序,每一次循环都需要对应一条指令,这样的编程方式很不灵活。
所以需要引入变址寻址,则同样的程序执行流程如下:
从主存地址为2的位置开始说明
① ACC加法采用了变址寻址,EA=(IX)+A,这条指令的形式地址A指向了7这一主存地址,也就是数组第一个元素的存放地址,而变址寄存器IX的值为0,所以
(ACC)+(7+(IX))-->ACC 所以(ACC)=a[0]
② 接下来进行IX加法,也就相当于程序中的i++,再将IX与10进行比较,对应于程序的:
for(int i=0;i<10;i++)
③ 若i<10,则程序的执行流,跳转到主存地址为2的位置,即进行第二次的加法,由于现在IX=1,所以操作数放在(7+1)=8的位置,即a[1]的地址。
那么(ACC)+(7+(IX))-->ACC (ACC)=a[0]+a[1]
④ 若i=10,那么就不会条件跳转,而是执行ACC--->sum变量,即将所有数组之和赋值给sum变量
所以在数组处理过程中,可设定A为数组的首地址,不断改变变址寄存器IX的内容,便可很容易形成数组中任一数据的地址,特别适合编制循环程序。
这里补充硬件是如何实现数的“比较”?
1.通过"cmp指令"比较a和b(如cmp a,b),实质上是用 a-b
2.相减的结果信息会记录在程序状态字寄存器(PSW)中
信息如下,PSW中有几个比特位记录上次运算的结果:
进位/借位标志CF:最高位有进位/借位时CF=1
零标志 ZF:运算结果为0则ZF=1,否则ZF=0
符号标志SF:运算结果为负,SF=1,否则为0
溢出标志OF:运算结果有溢出OF=1,否则为0
3.CPU根据PSW的某几个标志位进行条件判断,来决定是否转移
举个例子:
如下图所示,记录a-b的结果,若a
注:汇编语言中条件跳转指令有很多种,如 je2 表示当比较结果为 a=b 时跳转到主存地址为2的位置。若采用无条件转移指令 jmp2 ,就不会管PSW的各种标志位,使PC的值为主存地址2。
注:汇编语言中条件跳转指令有很多种,如 je2 表示当比较结果为 a=b 时跳转到主存地址为2的位置。若采用无条件转移指令 jmp2 ,就不会管PSW的各种标志位,使PC的值为主存地址2。
注:汇编语言中条件跳转指令有很多种,如 je2 表示当比较结果为 a=b 时跳转到主存地址为2的位置。若采用无条件转移指令 jmp2 ,就不会管PSW的各种标志位,使PC的值为主存地址2。
具体想要学习的话,可以看这篇博客:http://t.csdnimg.cn/qN79z
(9)基址+变址复合寻址
在上述例子中,默认程序从主存地址为0的地址往后存放,因此,当IX为2时,则能定位到a[2]地址单元,也就是基址7+变址2=9主存地址
但若此程序从主存地址为100的地址开始存放,那么执行"ACC加法"时,就不能只用到变址寻址,而是需要基址寻址+变址寻址得到最终有效地址。
基址寻址:EA=(BR)+A
变址寻址:EA=(IX)+A
先基址后变址寻址:EA=((BR)+A)+(IX),即先把形式地址A+BR,使其指向a[0],接下来进行变址寻址,即+(IX),就能得到最终的有效主存地址109
注:实际应用中往往需要多种寻址方式复合使用(可理解为复合函数,因为每一种寻址方式都是要将形式地址A映射为有效地址EA,只是不同寻址方式映射规则不同,多种寻址方式复合,就是将不同映射规则结合起来,相当于数学中的复合函数)
(10)相对寻址
相对寻址把程序计数器PC的内容加上指令格式中的形式地址A而形成操作数的有效地址,即
EA=(PC)+A,其中A是相对于PC所指地址(下一条指令地址)的位移量,可正可负,补码表示。
如图所示,CPU从主存地址为1000的位置中取出指令,每当CPU取出一条指令,都会使PC指向下一条指令的存放地址。
若当前指令字长=2B,则PC+2
若当前指令字长=4B,则PC+4
因此取出当前指令后,PC可能为1002或1004,假设当前(PC)=1002
若采用相对寻址,则EA=(PC)+A---->EA=1002+A,所以A是相对于下一条指令的位移量
相对地址的作用:
如下图所示,“条件跳转”使用的是直接寻址的方式
若该for循环被挪动了位置,再按照之前直接寻址的方式进行解析,即跳转到主存地址为2的位置,则会出现错误。
所以引入相对寻址,若当前执行的指令为“条件跳转”,那么PC的值会自动+1,指向M+4主存地址,为了该for循环正常工作,可以让PC的值指向主存地址为M的位置,即M+4-4。
由于跳转指令本质是在修改PC的值,那么会把相对寻址得到的有效地址赋给PC,让PC重新指向主存地址为M的位置。
所以无论for循环被挪到哪一个位置,都不需要修改跳转指令的地址码,采用相对寻址,就能得到正确的结果。
优点:这段代码在程序内浮动时不用更改跳转指令的地址码
注:对于“ACC加法”,若挪动这一for循环的位置,数组的起始地址可能不是主存地址为7的位置,对于程序员而言,若挪动for循环的位置,还需要修改地址参数,显然是很麻烦的
可以采用“分段”方式,就是将程序分为程序段,数据段,用数据段专门存放数据。例如,将数组a存放在数据段的起始地址为7的位置,那么a存放的地址在段中的相对位置不变,也就是形式地址A不需要改变。如下图所示,相对地址7就不需要修改了。
优点:操作数的地址不是固定的,它随着PC值的变化而变化,并且与指令地址之间总是相差一个固定值,因此便于程序浮动(一段代码在程序内部的浮动)。
相对寻址广泛应用于转移指令。
注:
在基址寻址中说的程序浮动,指的是整段程序在内存中的浮动,而相对寻址说的程序浮动指的是一段代码在程序内部的浮动。
11)堆栈寻址
操作数存放在堆栈中,隐含使用堆栈指针(SP)作为操作数地址。
•硬堆栈
堆栈是存储器(或专用寄存器组)中一块特定的按"后进先出(LIFO)"原则管理的存储区,该存储区中被
读/写单元的地址是用一个特定的寄存器给出的,该寄存器称为堆栈指针(SP)。
如图所示,假设寄存器已被存满,SP指向栈顶元素(R0),由于只有4个寄存器,则用2个bit位就可以表示所有寄存器的编号(2^2=4)
假设需要使用堆栈的两个栈顶元素完成一次加法操作,如图所示,加数和被加数需要放到ACC与X这两个寄存器中,通过ALU的计算,将结果输出到另一个寄存器中
记栈顶单元为Msp,首先POP ACC,即弹出栈顶元素,放到ACC寄存器中,那么SP指针+1,指向次栈顶元素
接下来POP X,再将栈顶元素弹出,放到X寄存器中,SP指针继续+1
接下来将加法的结果放到寄存器Y中,即ADD Y (ACC)+(X)-->Y
最后PUSH Y,将运算结果压回栈顶。首先SP=SP-1,然后再将Y的值放到SP指向的寄存器中
可以看到POP ACC和PUSH Y,这两个指令所存放的位置是被隐含在SP中的
出栈时,首先弹出SP指向的元素,接着(SP)+1--->SP
入栈时,首先(SP)-1--->SP,接着再将想要存的元素存到SP所指的寄存器中。
总结:
栈顶在小地址方向
栈顶在大地址方向
•软堆栈
以上堆栈寻址的实现是采用专门的寄存器的,可以将其称为硬堆栈,还有一种为软堆栈,即从主存中划分一片区域作为堆栈
采用硬堆栈与软堆栈的区别:
① 若采用软堆栈,弹出栈顶元素或压入一个元素就需要进行访存,而采用硬堆栈,由于堆栈元素都存放在寄存器中,无论弹出栈顶元素或压入一个元素都不需要进行访存,使用硬堆栈,CPU运行速度会更快。
注:这里指的是"指令执行期间",硬堆栈不需要访存,而软堆栈需要一次访存,在取指令时还是都需要访存的。
② 但是由于寄存器较贵,所以硬堆栈成本更高,而软堆栈成本更低。
实际系统中,通常会使用软堆栈,函数调用时保存的当前函数的相关信息,都会被保存在程序对应的软堆栈中。
总结:
8.CISC和RISC
CISC和RISC是指令系统的两种设计方向:
(1)CISC(Complex instruction Set Computer)
一条指令完成一个复杂的基本功能。例如,x86架构,主要用于笔记本,台式机等。
但随着指令越来越复杂,出现了80-20规律:典型程序中80%的语句仅仅使用处理机中 20% 的指令
比如设计一套能实现整数、矩阵加/减/乘运算的指令集:
CISC的思路:除了提供整数的加减指令除之外,还提供矩阵的加法指令、矩阵的减法指令、矩阵的乘法指令,并且一条指令由一个专门的电路完成。而有的复杂指令用纯硬件实现很困难,所以采用“存储程序’的设计思想,由一个比较通用的电路配合存储部件完成一条指令。例如设置加、减、乘电路,并且由这几个电路一起完成矩阵乘法指令。
总结:
CISC可以提供很多复杂的指令,对于一些特别复杂的指令,无法使用某一硬件电路实现,就会采用微程序实现。
(2)RISC(Reduced instruction Set Computer)
一条指令完成一个基本“动作”;多条指令组合完成一个复杂的基本功能。例如,ARM架构,主要用于
手机,平板等。
比如设计一套能实现整数、矩阵加/减/乘运算的指令集:
RISC的思想:只提供整数的加减乘指令
一条指令一个电路,电路设计相对简单,功耗更低
RISC中指令相对简单,功能单一,可以较方便地设计出定长指令结构,指令执行时间相差不大,所以适用于"并行","流水线"
总结:
这里特别说明:
① 对于CISC而言,可访存指令是不加限制的,而RISC中,可访存指令只有Load(某数据从主存中取出)/Store(某数据放入主存)指令,若某程序的乘法指令可以访存,那么一定是CISC
在CISC中,乘法指令会将需要相乘的数从主存中取出,放到相应的寄存器中进行乘法操作,不会过多占用寄存器
在RISC中,需要用Load指令访存,将数据从主存取出,放到寄存器中,再用乘法指令对两个寄存器的值相乘,这样就会占用较多寄存器
② CISC中,绝大多数为微程序控制。RISC中,绝大多数为组合逻辑控制。
③ CISC中,由于各指令执行时间相差较大,所以指令流水线会比较困难,但是也可以通过一定方式实现。RISC中,各指令执行时间绝大多数可以在一个周期内完成,所以较容易实现指令流水线。流水线会使CPU效率提高很多,所以RISC必须实现指令流水线。