计算机的指令,分为两部分。操作码(OP)和指令地址。每个指令的地址部分又分为两部分:寻址方式和形式地址(A)。形式地址有些情形下要通过一些转换,才能得到操作数的实际地址(EA)。
立即(数)寻址
这种方式下,操作数既不在内存也不在寄存器中,而是形式地址本身。这种寻址特征用#立即数
表示。
这个指令会直接把数据数本身放在指令中。比如PUSH #114514
会把数字114514压入堆栈。
优点
不必访问主存,不必访问寄存器,执行时间最短
缺点
立即数的大小受限。比起内存动辄32位起步的操作数,立即数能表示的仅仅是指令中留给形式地址的位数所能表示的数字范围。
访存次数
0
直接寻址
直接寻址的操作数在内存中。形式地址A
便是操作数所在的内存地址。实际地址就是形式地址。
EA = A
优点
简单,只需要1次访存
缺点
形式地址直接绑定了机器的物理地址,不适合多道程序的装入换出,也不适合程序的浮动
寻址范围
由指令中形式地址的比特位的数量决定
访存次数
1
寄存器寻址
寄存器寻址的操作数在寄存器中。形式地址Rx是操作数所在寄存器编号。
EA = Rx
优点
不需要访问主存,指令短(寄存器数量相比主存地址数量少很多)
缺点
寄存器价格昂贵,寄存器数量有限
寻址范围
CPU中的各个寄存器
访存次数
0
间接寻址
实际地址需要通过多次访存才能找到,就像在一个链表中爬到链表尾。
EA = (A)
, EA = ((A))
...
下图中展示的是2次间接寻址EA=((A))
优点
寻址范围大,程序灵活性高,修改寻址路径中的值就能修改寻址的结果
缺点
需要多次访存
访存次数
≥2ge 2≥2
寄存器间接寻址
寄存器间接寻址中,寄存器Rx存储了操作数所在的内存地址。即EA = (Rx)
优点
寻址范围大,访存次数比一次间接寻址少1次
相对寻址
相对寻址方式中的实际地址,是PC(程序计数器) 与形式地址之和,即EA = (PC) + A
优点
对于一个C语言函数的局部变量,使用相对寻址,可以让函数在编译后的段能在程序中浮动。 相对寻址广泛运用于转移指令(JMP
, JNZ
等)
基址寻址
基址寻址与相对寻址类似,实际地址为基址寄存器中的值加上形式地址,即EA = (BR) + A
。
优点
基址寻址主要面向操作系统,每个程序上处理机前,BR寄存器会被操作系统设置好,因此我们可以让多道程序上处理机进行调度。使得程序代码不需要硬编码主存的物理地址。
变址寻址
变址寻址时,实际地址为变址寄存器IA与形式地址之和,即EA = (IA) + A
优点
变址寻址面向用户,变址寻址,通常用于简化程序中连续内存空间的数据结构(如数组)的寻址问题。
堆栈寻址
在存储器中,有一块特定的按照先进后出(FILO)方式管理的一片区域称为堆栈。这块区域的栈顶指针为ESP
,通过PUSH
和POP
指令,能够往堆栈中压入数据和弹出数据。这两个指令的寻址方式即为堆栈寻址。
EA = ESP
优点
通过寻址,可以实现高级编程语言中函数的调用和返回特性。
隐含寻址
这种寻址方式,不需要在指令中显式给出操作数地址,而是在指令中隐含操作数的地址。比如ADD
指令的第二个操作数地址隐含在ACC
寄存器中。指令中只给出第一个操作数地址。
总结
寻址方式 | 寻址范围影响因素 | 表达式 | 访存次数 | 特点 |
---|---|---|---|---|
立即数寻址 | N/A | - | 0 | 指令执行时间最短,操作数大小受形式地址长度限制 |
直接寻址 | 指令形式地址长度 | EA = A |
1 | 访存次数只需要1次,但程序硬编码了主存的物理地址 |
寄存器寻址 | 寄存器数量 | EA = Rx |
0 | 访存次数更少,但寄存器造价昂贵数量有限 |
间接寻址 | 机器字长 | EA = (A) , EA = ((A)) ... |
≥2ge2≥2 | 灵活性高,但访存次数多 |
寄存器间接寻址 | 机器字长 | EA = (Rx) |
1 | 访存次数比1次间接寻址少1次 |
偏移寻址 | 机器字长,形式地址长度 | EA = (PC) + A |
1 | 使得程序段能浮动,通常用于跳转指令JMP 等指令 |
基址寻址 | 机器字长,形式地址长度 | EA = (BR) + A |
1 | 对于操作系统而言,基址寻址可以让程序在处理机上进行调度 |
变址寻址 | 机器字长,形式地址长度 | EA = (IX) + A |
1 | 对于用户而言,变址寻址可以让程序更方便地处理连续的数据结构,比如数组 |
堆栈寻址 | N/A | EA = ESP |
1 | 通常通过POP 和PUSH 修改栈顶寄存器ESP 。可以实现高级程序语言中的函数调用和返回 |
隐含寻址 | N/A | - | - | 根据指令约定隐含一个操作数在某个寄存器中 |