4.2.1指令寻址和数据寻址
4.2.1.1指令寻址:
顺序寻址: 取出指令后PC指向下一条需执行指令的地址。
1)顺序寻址:
定长指令字结构寻址: 假设指令字长 = 存储字长 = 16bit = 2Byte,且主存按字编址。则每次取出指令后PC + 1;若主存按字节编址,意味着每条指令都会占两个地址,则每次取出指令后PC + 2。 变长指令字结构寻址:指令字长 = 存储字长 = 16bit,主存按字节编址。假设相同颜色的是同一条指令。 假设从0开始,CPU无法判断指令长度,因此CPU会每次先读入一个字,并区分按字节编址还是按字编址,使得程序计数器PC + “一个指令长度”,本次叙述的是按字节编址,因此PC + 4,若按字编址,PC + 2。操作码被包含在第一个字,CPU根据操作码判断读取指令是几地址指令,由此确定指令占用多少字节,并继续读取后续。
2)跳跃寻址:
下一条指令的地址码不由程序计数器指出,而是由本条指令给出下条指令地址码的计算方式。 定长指令字结构寻址,指令字长 = 存储字长 = 16bit,主存按字编址。意味着每条指令占用一个字,两个字节;变长指令字结构寻址,与顺序寻址中变长指令字结构的情况可类比,不一一赘述,主存按字节编址的情况与顺序须知可以类比得出,也不赘述。 如上图,仍然假设CPU从0开始读入指令,从0~2都是顺序寻址,此时,执行完指令2时,PC指向的是指令3,接下来,CPU读入指令3,PC + 1,PC指向4,CPU执行指令3,指令3是JMP,无条件跳转指令,跳转到7,此时PC重新指向,指向7。
4.2.1.2 数据寻址:
确定本条指令的地址码指向的真实地址,是指如何在指令中表示一操作数的地址,与跳跃寻址并不相同。由于数据寻址的方式较多,为了便于区别,会在指令字的形式地址前面设置几个bit作为寻址方式位,这几位是寻址特征。每个形式地址前面都会有一个寻址方式位。
4.2.2 数据寻址的方式
一地址指令: 二地址指令: 介绍十种数据寻址方式,由于10 < 16 = 2^4^,因此十种情况用4个bit表示足以。假设指令字长 = 机器字长 = 存储字长,假设操作数是3。
4.2.2.1 直接寻址
指令字中的形式地址A就是操作数3的真实地址EA,CPU根据形式地址去主存中相应地址找到数据3并将其放入ACC中进行计算。取指令,执行指令一共访问主存两次。直接寻址过程简单,但操作数的地址范围有限,且操作数地址发生变化时指令需要再修改。
4.2.2.2 间接寻址
指令的形式地址码A指向主存中某个有效地址EA,EA中存储着操作数的真实地址,可以用EA = (A)来表示,其中(A)表示地址A所指向的主存单元里的数据,取指令访问存储一次,执行指令访问存储两次一共三次。间接寻址扩大了寻址范围,便于编写汇编程序,但是由于需要多次访存,因此执行指令速度会慢。 间接寻址可以多层“套娃”,间接寻址可以与C语言中的一级指针、二级指针、多级指针类比理解。
4.2.2.3 寄存器寻址
指令中的形式地址码Ri指向某个编号为Ri的寄存器寄存器中存放操作数,取指令访存一次,执行指令不需要访存。寄存器寻址执行指令不需要访存,因此执行速度快,支持向量或者矩阵运算,但由于价格昂贵,寄存器个数有限。
4.2.2.4 寄存器间接寻址
指令中Ri指向某个编号为Ri的寄存器,寄存器中存放操作数在主存中的真实地址EA,EA = (RI),取指令访存一次,执行指令访存一次共两次。寄存器间接寻址比一般间接寻址更快。
4.2.2.5 隐含寻址
如两个操作数的运算,一个操作数的地址存放在指令的形式地址码A中,另一个操作数B在ACC中,操作数B被指令隐含在ACC中。缩短了指令长度,但需要增加存储操作数或者隐含操作数地址的硬件。
4.2.2.6 立即寻址
指令的形式地址码就是操作数本身,一般用补码表示,#表示立即寻址特征。取指令访存一次,执行指令不访存,指令执行时间短,但形式地址码的位数限制了操作数的表示范围。
4.2.2.7 基址寻址指令中形式地址码A加上基址寄存器中的内容就是操作数的有效地之EA,EA = (BR) + A,如上图,CPU中的基址寄存器可以,可以采用专用的寄存器,也可以采用通用寄存器,但是若采用通用寄存器,需要在指令中用若干bit表示为Ri,来指明使用了编号Ri的通用寄存器作为基址寄存器。
关于基址寻址过程:
还是采用讲义里的笔记截图,假设这一段程序的指令,在主存中的地址不是从0开始,而是从100或者其他地址开始。程序运行前,CPU将BR的值修改为当前要执行程序的起始地址,存放到操作系统的程序控制块PCB中。PC指向程序指令起始地址100,第一条指令是取出操作数a,a存放在主存地址码为105 = 100 + 5的位置。基址寻址适用于多道程序设计,可扩大寻址范围,可用于编写经常浮动的程序。
4.2.2.8 变址寻址
指令中形式地址码A加上基址寄存器中的内容就是操作数的有效地之EA,EA = (IX) + A,如上图,CPU中的基址寄存器可以,可以采用专用的寄存器,也可以采用通用寄存器,但是若采用通用寄存器,需要在指令中用若干bit表示为Ri,来指明使用了编号Ri的通用寄存器作为基址寄存器。
关于变址寻址过程:
假设要执行一段程序
for(int i = 0, i < 10; i ++)
{
sum = sum + a[i];
}
PC指向第二条指令,PC + 1,取操作数到IX中,此时IX为0,下一条指令的形式地址指向7,则ACC中的操作数0,与 7 + (IX) 得到的地址中的数据相加再放到ACC中,完成一次数组元素加法操作,执行指令IX + 1,则是for循环中的i++,比较IX中的数据与10,则是执行判断i < 10。执行指令5,满足指令中的条件,跳转到指令2,重复前述步骤。后续指令执行较为简单,不再赘述。变址寻址适用于循环程序。
4.2.2.9 相对寻址
指令中的形式地址码A加上PC中的内容形成的有效地址码EA,EA = (PC) + A,A是相对于PC的偏移量,可正可负,用补码表示。
仍然是讲义中的例子,假设把for循环移动到其他位置,此时就需要用相对寻址,假设for循环程序的起始地址是M,则执行指令到M + 3时,PC + 1 = M + 4,此时(PC) + A,得到M,完成一次循环。相对寻址使得for循环有关程序可以在整个程序内任意浮动,而不用修改指令中的形式地址。
4.2.2.10 堆栈寻址
操作数放在堆栈中,使用堆栈指针(SP)作为操作数有效地址,按照FIFO先进先出的原则管理堆栈存储器。可分为硬堆栈和软堆栈,硬堆栈是寄存器堆栈,不需要访存就能完成寻址;从主存中划分出一段存储空间来作为堆栈的是软堆栈,软堆栈需要一次访存。 CPU从堆栈区按顺序,取出栈顶元素放到ACC中,SP + 1,指向次栈顶元素,取出次栈顶元素放到X中。计算完毕,把计算结果压入栈,SP - 1,完成一次加法操作。如下图。 有些情况下栈顶的位置可能在地址数值较小的位置,也可能在地址数值较大的位置,需要详细区分。 计算上述加法过程中,硬堆栈不访存,软堆栈每次压入栈或者弹出栈的操作,都需要访存。