数据寻址(2)

数据寻址(2)

偏移寻址

  1. 基址寻址
  2. 变址寻址
  3. 相对寻址
  • 三种的区别:在于偏移的“起点”不一样
  • 三种的相同点:访存次数——指令执行期间都是1次。

数据寻址(2)

  1. 第一个:运行到第 3 行,就让PC=7,跳跃到7。这里当然没有错误。但是,当我们无法从主存起始值为0的地方开始呢?

  2. 第二个:我们起始位置是100,到了103我们又跳到7?当然不是,我们的本意是要到这个程序的第7行。所以,这个7应该视为从100起的偏移量,即第107行。所以,要改变对它的解读方式

  3. 第三个:运行到第 103 行,此时PC=104 。故第 103 行的3的意思是“让PC在原有基础上+3”,这样PC=107

基址寻址

基址寻址:以程序的起始存放地址作为“起点”

  • 将指令格式中的形式地址A 加上 CPU中基址寄存器BR(Base address Register)的内容,而形成操作数的有效地址
  • EA=(BR)+A。

一个专门的基址寄存器【操作系统中的重定位寄存器】

数据寻址(2)

在指令中指明,要将哪个通用寄存器作为基址寄存器使用

数据寻址(2)

  • 要用几个bit来指明寄存器? 根据通用寄存器总数判断—— 比如一共有8个,那么就2^3=8,故 3bit。
  • 由用户决定哪个寄存器作为基址寄存器时,但其内容仍由操作系统确定,程序员不可以修改BR的内容
  • 在程序执行过程中,基址寄存器的内容不变(作为基地址),形式地址可变(作为偏移量)。

例:执行主存中的一段从100起始的代码

int a=2 ,b=3,c=1,y=0;
void main() {
	y=a*b+c;
}

数据寻址(2)

  • 这个程序,从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];

数据寻址(2)

  • 第 0 行:立即寻址(#),得到 0 并给到 ACC

  • 第 1 ~ 10 行:依次完成10次数组和相加。

  • 第 12 行:存储数据

  • 共12条指令。导致编程麻烦。

  • 如果需要100次数组和相加。岂不是还需要再加上90次?

采用变址寻址后

for(int i=O; i<10; i++)	sum += a[i];

数据寻址(2)

  • 第 0 行:立即寻址(#),得到 0 并赋值给 ACC
  • 第 1 行:立即寻址(#),得到 0 并赋值给 IX
  • 第 2 行:变址寻址,地址码是给出数组的初始地址,
  • 第 3 行:立即寻址(#),得到 1 并给 IX 加上
  • 第 4 行:立即寻址(#),得到 10 ,然后与 IX 内含的数比较大小
  • 第 5 行:直接寻址,操作码是条件跳转,地址码是2。
    • 当上一行的比较结果若符合循环条件,则又跳转,使得 PC = 2
    • 当不符合循环条件,则 PC + 1
  • 第 6 行:存储数据
  • 就这样,通过每一次给变址寄存器 IX ➕ 1 ,使得轻松完成了数组的循环。

变址寻址的作用

数组处理过程中,可设定A为数组的首地址,不断改变变址寄存器IX的内容,便可很容易形成数组中任一数据的地址,特别适合编制循环程序。

基址寻址&变址寻址复合

数据寻址(2)

实际中往往是多个复合使用的:

基址寻址:EA = (BR)+ A

变址寻址:EA = (I X)+ A

先基址寻址后变址寻址: EA = (IX) + ((BR)+ A )

相对寻址

  • 把程序计数器 PC 的内容加上指令格式中的形式地址 A 而形成操作数的有效地址

    • 其中A是相对于PC所指地址的位移量,可正可负,补码表示。
  • EA=(PC)+A

  • 即:以程序计数器器PC所指地址作为“起点”

  • 注意A不是相对于当前指令地址的位移量而是相对于下一条指令的指令的偏移量

数据寻址(2)

例:挪动一段循环代码

比如说,随着代码越写越多,想要在自己写的程序中挪动这一段循环代码到其他位置,就要用到相对寻址。

for(int i=0;i<10;i++)	sum += a[i];

挪动前

数据寻址(2)

  • 此时可以正常运行。
  • 但是如果我们往后挪动呢?

挪动后

数据寻址(2)

  • 观察第 M+3 行:操作码:条件跳转;地址码:2 此处挪动到了M+3后,条件再次跳转到2,必然发生错误。

  • 执行到 M+3 时,PC = M + 4

  • 所以我们修改第 M+3 行:操作码:条件跳转;地址码:-4(补码)

  • EA = ( PC )+ - 4 //就是说改成条件跳转回到 M

    修改后

数据寻址(2)

  • 此时不论你把这段程序放在哪里,都可以正常执行。

  • 另注: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

数据寻址(2)

上一篇:侯捷 c++ 内存管理笔记 p1-p6


下一篇:哈希加密详解和md5、sha1、sha256、Java 工具类