主存储器寻址是所有计算机系统中都普遍采用的一类寻址方式,其寻址种类也最为复杂。主存储器寻址的指令格式主要有:
OPC M
OPC M, M
OPC M, M, M
主存储器寻址的基本类型有直接寻址方式、间接寻址方式和变址寻址等三种。对于后两种寻址方式,还有一些特殊的寻址方式。我们仍然假设有效地址为EA,在指令的地址码字段中给出的地址为A,变址寄存器为X,地址的增量为d。对于各种主存储器寻址方式,分别叙述如下:
1.直接寻址方式
直接寻址方式是在指令中直接给出参加运算的操作数或存放运算结果的主存地址,即在指令中直接给出有效地址。
有效地址:EA = A
在早期生产的计算机及目前的某些专用计算机中用得比较多。随着主存储器容量的不断扩大及虚拟存储器的普及,这种寻址方式暴露出了许多弱点。
首先,它需要很长的地址码,特别在二地址及三地址指令中,这一矛盾更为突出。通常的小型及微型计算机,表示一个主存地址要二进制30位左右,因此,有限长度的指令无法容纳如此长的地址码。
其次,为了实现程序循环及高效处理数组运算等,程序设计中修改数据的地址是必不可少的。采用直接寻址方式编写的程序,如果要修改数据地址就必须修改程序中的指令本身,采用这种方法编写的程序没有再入性,这是现代程序设计思想所不能接受的。
另外,目前使用的操作系统多为多任务或多用户系统,采用直接寻址方式编写的程序会给操作系统的作业调度带来极大的不便,因为,多任务及多用户操作系统要求程序能够在主存中浮动,所以,必需要有其它寻址方式来支持。
2.间接寻址方式
间接寻址方式在指令中给出的是操作数地址的地址,或者是目的地址的地址,必须先访问一次主存储器才能得到有效地址。
有效地址:EA=(A)或EA=@A
3.变址寻址方式
采用变址寻址方式时,需要设置一个或多个变址寄存器。变址寄存器的长度由主存储器的寻址空间决定,例如,主存储器的寻址空间为4GB,则变址寄存器的长度需要32位。也可以把某一个或几个通用寄存器兼作变址寄存器来使用。变址寄存器的主要作用是用来存放数组的基地址。
有效地址:EA = A +(X)
在指令中给出变址寄存器的编号(如果只有一个变址寄存器,可以隐含)和地址的偏移量。
当指令在执行时,用一个硬件加法器,把变址寄存器中给出的基地址与指令中给出的地址偏移量作算术加法,相加的结果就是有效地址。
间接寻址方式与变址寻址方式的设计目标都是为了解决操作数地址的修改问题。它们都能做到,在程序设计过程中能够对操作数的地址进行修改,而不必去修改程序中的指令本身。例如,对于数组运算,通常要用一个循环程序对数组中的各个元素进行操作,如果数组的各个元素存放在一个连续的内存空间中,在不允许修改程序的前提下,必须通过修改操作数的地址才能连续访问到数组中的数据。
原则上,在一台计算机系统中,只需要设置间接寻址方式与变址寻址方式中的任何一种即可。例如,在IBM公司生产的大中型计算机系统中,只有变址寻址方式,没有间接寻址方式。在许多小型及微型计算机系统中,只有间接寻址方式,没有变址寻址方式。也有一些计算机系统,间接寻址方式和变址寻址方式两种都有。
那么,就会提出这样一个问题:在一台计算机系统中,如何选择间接寻址方式与变址寻址方式?他们各有什么优点与缺点?下面,我们通过一个简单的例子,分析这两种寻址方式的特点。
例3.1:一个由N个元素组成的数组,已经存放在主存储器的连续存储单元中,现要把它搬到主存储器的另一个连续的存储单元中,源数组的起始地址为AS,目标数组的起始地址是AD,不必考虑可能出现的存储单元的重叠问题。为了编程简单,采用一般的两地址指令编写程序。
首先,用间接寻址方式编写程序如下:
START:MOVE ASR, ASI ;保存源数组的起始地址,为了程序有在入性
MOVE ADR, ADI ;保存目标数组的起始地址
MOVE NUM, CNT ;保存数据的个数
LOOP: MOVE @ASI, @ADI ;用间接寻址方式传送数据
INC ASI ;源数组的地址增量
INC ADI ;目标数组的地址增量
DEC CNT ;个数减1
BGT LOOP ;测试N个数据是否传送完
HALT ;停机
ASR: AS ;源数组的起始地址
ADR: AD ;目标数组的起始地址
NUM: N ;需要传送的数据个数
ASI: 0 ;当前正在传送的源数组地址
ADI: 0 ;当前正在传送的源数组地址
CNT: 0 ;剩余数据的个数
为了程序具有再入性,前3条指令是必须的,数据存放单元要分别重复设置一份也是必须的。
然后,用变址寻址方式编写程序如下:
START:MOVE AS, X ;把数组的起始地址送入变址寄存器
MOVE NUM, CNT ;保存数据个数,为了程序具有再入性
LOOP: MOVE (X), AD-AS(X) ;AD-AS为地址偏移量,在汇编时计算
INC X ;增量变址寄存器
DEC CNT ;个数减1
BGT LOOP ;测试N个数据是否传送完成
HALT ;停机
NUM: N ;需要传送的数据个数
CNT: 0 ;剩余数据的个数
比较以上两个程序,可以很明显地看出,采用变址寻址方式编写的程序简单、易读。对程序员来说,两种寻址方式的主要差别如下:
间接寻址方式:间接地址在主存储器中,没有偏移量。
变址寻址方式:基地址在变址寄存器中,带有偏移量。
由此产生的两种寻址方式的优点与缺点是:
(1) 实现的难易程度。间接寻址方式实现起来很容易,只需要增加一条从主存储器的数据寄存器到地址寄存器的数据通路即可。实现变址寻址方式需要增加较多的硬件,需要一个硬件的加法器,一个或多个变址寄存器(也可以与通用寄存器合用)。
(2) 指令的执行速度。采用间接寻址方式编写的程序,执行速度很慢。读写一个操作数至少需要访问两次主存储器,第一次访问主存储器读取有效地址,第二次访问主存储器才是读或写操作数。
执行上述程序中的MOVE @AS, @AD这条指令,至少需要访问主存储器5次,其中,第一次访问主存储器,读取指令本身,第二、第三次访问主存储器读到源操作数,再经过两次访问主存储器操作,才能把数据送入主存储器的目标地址单元中。
采用变址寻址方式编写的程序,执行速度比较快。有效地址通过硬件加法器直接产生,不需要访问主存储器。如执行上述程序中的MOVE (X), AD-AS(X) 这条指令,只需要访问主存储器3次。
(3)对数组运算的支持。变址寻址方式比较好,间接寻址方式较差,这是因为变址寻址方式可以带有偏移量。基地址加偏移量能够很有效地表示向量、矩阵等数据。
另外,对于变址寻址方式和间接寻址方式,还有以下几种特殊的寻址方式:
4.多重间接寻址方式;
按照指令中给出的地址A访问主存储器得到的不是有效地址EA,而是有效地址EA的地址。
间接寻址可以只进行一次,也可以连续进行多次。多数计算机系统采用一次间接寻址方式,这种间接寻址方式只要用指令中给出的地址码去访问主存储器,就能直接得到操作数的有效地址。
有效地址EA =((A))或 EA=@(A)
采用多级间接寻址时,第一次间址的标志由指令给出,以后各次的间址标志要由紧接着访问主存储器所取出来的地址码给出。如果取出的地址码的间址标志位(通常指定最高位)为"1",则要用除去标志位后的部分作为地址码继续访问主存储器,直至取出来的地址码的间址标志位为"0"时为止,这时,除去间址标志位之后的地址码即为有效地址。
通常划出主存储器最低端的一小部分存放间接地址,因此,采用间接寻址方式时,指令中需要表示的地址码的长度可以很短。另外,也可以用寄存器来存放间接地址,这样,指令中需要表示的地址码的长度就更短。
变址寻址方式有两种特例,即相对寻址方式和基址寻址方式。
5.相对寻址方式
当变址寄存器就是程序计数器PC时称为相对寻址方式。
有效地址EA =(PC)+ A
采用相对寻址方式编写的程序本身就具有浮动性,称为位置无关代码(PIC码),因此,相对寻址方式为程序的连接装配及在主存中的浮动调度提供了极大的方便。
6.基址寻址方式
基址寻址方式是为支持程序动态重定位而设置的,实际上,它也是一种变址寻址方式,所不同的是:基址寻址方式中的变址寄存器是程序动态重定位时使用的基址寄存器。
有效地址EA =(B)+ A;式中B为基址寄存器
在有些计算机系统(如IBM公司生产的大型中型计算机)中,既有变址寻址方式,又有基址寻址方式,这时,在指令执行过程中,对于每一个操作数都要进行两次变址运算,即做两次加法运算才能得到操作数的地址。
与寄存器间接寻址一样,在主存储器的间接寻址方式和变址寻址方式中也有自动增(减)寻址方式。
7.自动变址
从上面的例子中看到,无论采用间接寻址方式,还是采用变址寻址方式编写程序,对于数组运算,都必须有对地址进行增量的指令。在采用间接寻址方式编写的程序中,有两条指令分别对源数组和目标数组的地址指针进行增量。在采用变址寻址方式编写的程序中,有一条指令对变址寄存器进行增量。为了省去这些对地址进行增量的指令,在许多计算机系统中对于间接寻址方式和变址寻址方式都增加了自动变址的功能。
上例中,对于采用间接寻址方式编写的程序,只要把指令:
MOVE @AS, @ADG
改为: MOVE (AS)+, (AD)+
紧接在下面的两条分别对AS和AD指针作增量的指令就可以省去。
同样,在采用变址寻址方式编写的程序中,把指令:
MOVE (X), AD-AS(X)
改为: MOVE (X), AD-AS(X)+
紧接在下面的一条对变址寄存器作增量的指令就可以省去。
地址增量的单位,要根据具体机器所采用的编址方式和数据元素的长度等关系来确定,例如,对于采用字节编址的机器,如果数据元素的长度是二进制16位,则增量单位是2,如果数据元素的长度是二进制32位,则增量单位是4。
地址增量的先后关系也很有讲究,有如下几种方式:
第一种,先用后增,先减后用方式。程序中的写法是:A(X)+,-A(X),或A(X++),A(--X)。这种方式多用于有后进先出堆栈,而且堆栈指针指向栈顶元素的计算机系统中。
对于A(X)+,先计算有效地址EA =A+(X),然后使变址寄存器指向下一个地址X = X + d。其他自动变址方式,按类似的方法计算。
第二种,先增后用与先用后减方式。程序中的写法是:+A(X),A(X)-,或A(++X),A(X--)。这种方式多用于有后进先出堆栈,而且堆栈指针指向栈顶第一个空元素的计算机系统中。
第三种,先增后用与先减后用方式:程序中的写法是:+A(X),-A(X),或A(++X),A(--X)。这种方式多用于有没有后进先出堆栈的计算机系统中。
对于间接寻址方式的自动变址,只要把上面的括号前的A去掉,括号中的X改为A。
8.前变址与后变址
在既有变址寻址方式,又有间接寻址方式的计算机系统中,先做变址运算还是先做间址运算,需要事先定义。有效地址EA的计算方法有如下两种:
第一种,前变址寻址方式,有效地址的计算过程是:EA=((X)+A)。
第二种,后变址寻址方式,有效地址的计算过程是:EA=(X)+(A)。
变址寻址方式中的偏移量是带有符号的,通常用补码表示,这样,不仅可以有向前的偏移,也可以有向后的偏移。
偏移量的长度一般短于基地址的长度,在做加法时,一定要把偏移量的符号扩展,直至与基地址的长度相同。例如,某机器的偏移量为二进制8位,有一个用16进制补码表示的偏移量F3,基地址为二进制16位,有一个用16进制表示的基地址05CD,正确的做法是:在做加法之前,首先要把偏移量的符号扩展8个二进位,成为FFFD,再与基地址相加,结果的有效地址是:05CD+FFF3=05C00。