数据寻址(2)
偏移寻址
- 基址寻址
- 变址寻址
- 相对寻址
- 三种的区别:在于偏移的“起点”不一样
- 三种的相同点:访存次数——指令执行期间都是1次。
-
第一个:运行到第 3 行,就让PC=7,跳跃到7。这里当然没有错误。但是,当我们无法从主存起始值为0的地方开始呢?
-
第二个:我们起始位置是100,到了103我们又跳到7?当然不是,我们的本意是要到这个程序的第7行。所以,这个7应该视为从100起的偏移量,即第107行。所以,要改变对它的解读方式
-
第三个:运行到第 103 行,此时PC=104 。故第 103 行的3的意思是“让PC在原有基础上+3”,这样PC=107
基址寻址
基址寻址:以程序的起始存放地址作为“起点”
- 将指令格式中的形式地址A 加上 CPU中基址寄存器BR(Base address Register)的内容,而形成操作数的有效地址
- 即EA=(BR)+A。
一个专门的基址寄存器【操作系统中的重定位寄存器】
在指令中指明,要将哪个通用寄存器作为基址寄存器使用
- 要用几个bit来指明寄存器? 根据通用寄存器总数判断—— 比如一共有8个,那么就2^3=8,故 3bit。
- 由用户决定哪个寄存器作为基址寄存器时,但其内容仍由操作系统确定,程序员不可以修改BR的内容。
- 在程序执行过程中,基址寄存器的内容不变(作为基地址),形式地址可变(作为偏移量)。
例:执行主存中的一段从100起始的代码
int a=2 ,b=3,c=1,y=0;
void main() {
y=a*b+c;
}
-
这个程序,从100开始存放。例如变量a的形式地址为A = 5,但是实际存放地址为 EA = 105,必须使用基址寻址了。
-
右边表格的每个地址码都加上100,就得到目标结果。即程序运行前,CPU将BR的值修改为该程序的起始地址
-
所以,程序可以在主存中浮动。
优点:
- 便于程序“浮动”,可用于编制浮动程序(整个程序在内存里边的浮动)。
- 可扩大寻址范围(基址寄存器的位数大于形式地址A的位数);由于A本来比较短,但是在R中内容比较大,就可以跟着范围变大。
- 用户不必考虑自己的程序存于主存的哪一空间区域,故方便实现多道程序并发运行,因为主存中可以有多个程序同时存在。
变址寻址
- 有效地址 EA 等于指令字中的形式地址A与变址寄存器 IX 的内容相加之和
- 即EA = (IX) + A
- 其中 IX 可为专用变址寄存器(BR),也可用通用寄存器作为变址寄存器(统称IX)。
- 区别注:变址寄存器是面向用户的,在程序执行过程中,变址寄存器的内容可由用户改变 IX 作为偏移量),形式地址A不变(作为基地址)。程序员自己决定从哪里作为“起点”
例:对某数组求和
采用变址寻址前
for(int i=O; i<10; i++) sum += a[i];
-
第 0 行:立即寻址(#),得到 0 并给到 ACC
-
第 1 ~ 10 行:依次完成10次数组和相加。
-
第 12 行:存储数据
-
共12条指令。导致编程麻烦。
-
如果需要100次数组和相加。岂不是还需要再加上90次?
采用变址寻址后
for(int i=O; i<10; i++) sum += a[i];
- 第 0 行:立即寻址(#),得到 0 并赋值给 ACC
- 第 1 行:立即寻址(#),得到 0 并赋值给 IX
- 第 2 行:变址寻址,地址码是给出数组的初始地址,
- 第 3 行:立即寻址(#),得到 1 并给 IX 加上
- 第 4 行:立即寻址(#),得到 10 ,然后与 IX 内含的数比较大小
- 第 5 行:直接寻址,操作码是条件跳转,地址码是2。
- 当上一行的比较结果若符合循环条件,则又跳转,使得 PC = 2
- 当不符合循环条件,则 PC + 1
- 第 6 行:存储数据
- 就这样,通过每一次给变址寄存器 IX ➕ 1 ,使得轻松完成了数组的循环。
变址寻址的作用
数组处理过程中,可设定A为数组的首地址,不断改变变址寄存器IX的内容,便可很容易形成数组中任一数据的地址,特别适合编制循环程序。
基址寻址&变址寻址复合
实际中往往是多个复合使用的:
基址寻址:EA = (BR)+ A
变址寻址:EA = (I X)+ A
先基址寻址后变址寻址: EA = (IX) + ((BR)+ A )
相对寻址
-
把程序计数器 PC 的内容加上指令格式中的形式地址 A 而形成操作数的有效地址
- 其中A是相对于PC所指地址的位移量,可正可负,补码表示。
-
EA=(PC)+A
-
即:以程序计数器器PC所指地址作为“起点”
-
注意:A不是相对于当前指令地址的位移量,而是相对于下一条指令的指令的偏移量。
例:挪动一段循环代码
比如说,随着代码越写越多,想要在自己写的程序中挪动这一段循环代码到其他位置,就要用到相对寻址。
for(int i=0;i<10;i++) sum += a[i];
挪动前
- 此时可以正常运行。
- 但是如果我们往后挪动呢?
挪动后
-
观察第 M+3 行:操作码:条件跳转;地址码:2 此处挪动到了M+3后,条件再次跳转到2,必然发生错误。
-
执行到 M+3 时,PC = M + 4
-
所以我们修改第 M+3 行:操作码:条件跳转;地址码:-4(补码)。
-
EA = ( PC )+ - 4 //就是说改成条件跳转回到 M
修改后
-
此时不论你把这段程序放在哪里,都可以正常执行。
-
另注:ACC加法指令的地址码,是采用分段的方式解决。程序段存放程序,数据段存放数据我们给个段落,专门存放数组a[ ]
优点:
- 便于程序浮动(一段代码在程序内部的浮动)。
- 相对寻址广泛应用于转移指令。
与基址寻址的区别
BR中也说了程序的浮动,区别:
-
基址寻址:整段程序在内存中的浮动
-
相对寻址:一段代码在程序内部的浮动
硬件层面是如何比较 a>b
硬件视角:
- 通过"cmp指令”比较a和b(如cmp a,b) ,实质上是用 a-b
- 相减的结果信息会记录在程序状态字寄存器中(PSW)【标志寄存器】
- 根据PSW的某几个标志位进行条件判断,来决定是否转移
- 汇编语言中,条件跳转指令有很多种
- 如 je 2 【jump when equal】 表示当比较结果为 a=b 时跳转到 2 ,就是令PC=2
- 如 jg 2 【jump when greater】 表示当比较结果为 a>b 时跳转到 2,就是令PC=2
- 无条件转移指令 jmp 2:不管PSW的各种标志位,就直接令PC=2