指令寻址和数据寻址

“寻址”这个词在本章里指两件完全不同的事:

  • 指令寻址:下一条指令的地址从哪来——答案永远落在 PC 上
  • 数据寻址:操作数的地址从哪来——答案落在有效地址 EA 上

两者的机制其实是同一套(这是本节最省事的一个发现),但它们的结果送往不同的目的地:一个送进 PC,一个送去取数。分清这一点,4.2 就只剩下一件事要学。

机制

指令寻址:只有两种

顺序寻址:,取指的同时自动完成。

那个 不一定是 1,这是本节最高频的计算陷阱:

指令字长编址单位
  • 按字编址、单字长指令 →
  • 按字节编址、32 位定长指令 →
  • 变长指令 → 不是常数,要等译码器确定本条指令长度后才知道(见 4.1.4)

跳跃寻址:由转移类指令给出新的 PC 值。跳跃之后并不是”一直跳”——新值装进 PC 后,机器立刻回到顺序寻址。 所谓”跳跃”只是往 PC 里塞了一个非顺序的值这一个动作。

关联对照:跳跃寻址没有自己的一套方法,它复用数据寻址方式

转移指令的目标地址怎么算?和取操作数地址用的是同一批寻址方式,只是算出的 EA 送进 PC 而不是送去访存:

转移指令写法用的是哪种寻址方式送 PC 的值
JMP 2000H直接寻址
JMP *(2000H)间接寻址主存 2000H 单元的内容
JMP R1寄存器寻址
JMP $+8PC 相对寻址

所以 4.2.2 那十种寻址方式学一遍,指令寻址和数据寻址一起解决。 教材把它们分成两节讲,是按”结果送哪儿”分的,不是按”怎么算”分的。

数据寻址:指令里多一个字段

一旦支持多种寻址方式,指令必须说清用的是哪一种,于是地址码那一半再拆开:

寻址特征形式地址

寻址特征字段的位数决定了这台机器最多支持几种寻址方式: 位 → 最多 种。这是计算题的常见一问。

形式地址 A 与有效地址 EA

这是整个 4.2 的核心一对,也是”寻址方式”这个概念存在的全部理由:

形式地址 有效地址
在哪写在指令里的那几位算出来的
是什么计算 EA 的原料操作数真正所在的地址
谁决定它们的关系——寻址方式
寻址方式寄存器内容主存内容

4.1.2 里指令字长不够用的那场争夺,出路就在这里:当 装不下一个完整地址时,就让它只装”原料”,剩下的从寄存器里补。 12 位的 配一个 32 位基址寄存器,照样能寻遍 4 GB 空间。

一个地址要走多少层

用户在 4.2.2 遇到的几乎全部困惑,根子都在拿两个不同层次的地址互相比较。所以先把整条链摆出来——这是本章的第二条主线:

graph TD
    S["源码符号<br/>L1 / arr / printf"] -->|"汇编器 + 链接器<br/>符号解析·重定位"| A["形式地址 A<br/>(指令里的那几位)"]
    A -->|"★寻址方式 4.2.2<br/>加寄存器·加位移·再访存"| EA["有效地址 EA<br/>= 逻辑地址"]
    EA -->|"分段<br/>段基址 + EA"| LIN["线性地址"]
    LIN -->|"分页 MMU<br/>页表 / TLB"| PA["物理地址"]
    PA -->|"Cache 划分<br/>标记 组号 块内"| C{"Cache<br/>命中?"}
    C -->|命中| HIT["取自 Cache"]
    C -->|缺失| MM["主存译码<br/>片选 + 片内行列"]
    MM --> CELL["存储单元"]
    classDef here fill:#ffe6cc,stroke:#d79b00,stroke-width:3px
    classDef co3 fill:#e1f5fe,stroke:#0288d1
    classDef pre fill:#e8e8e8,stroke:#888
    class A,EA here
    class LIN,PA,C,MM,CELL,HIT co3
    class S pre
层输入 → 输出谁在做在哪一节
符号解析符号 → 形式地址汇编器 / 链接器(静态)4.1.1
寻址方式形式地址 → EACPU 内的地址计算4.2.2
分段EA → 线性地址段部件OS 3.1.4
分页线性地址 → 物理地址MMU + 页表/TLB3.6.2
Cache 划分物理地址 → 标记/组号/块内Cache 控制器3.5.3
主存译码物理地址 → 片选 + 行列地址译码器3.3.3

用法是一句话:碰到”这是什么地址”的疑问,先定位它在这条链的哪一层。 上下相邻的两层永远是”输出→输入”的关系,不是同一层的两种做法,因此不能拿来比较优劣、也不能互相替代。4.2.2 里所有关于”基址寄存器 vs 段寄存器”的纠结,用这一句就能拆开。

边界

PC 的增量在取指周期就完成,早于执行周期。 所以执行 JMP 时,PC 里装的已经是下一条指令的地址而不是当前指令的地址。PC 相对寻址的基准就是这个已经加过的值——这是 4.2.2 最容易错的一处,也是整章最高频的计算陷阱。

“跳跃寻址”不是一种寻址方式的名字,它是”指令寻址的一种情形”。 具体用哪种方式算目标地址,仍从 4.2.2 那十种里挑。判断题若说”跳跃寻址与相对寻址是同一概念”,错。

顺序寻址的 不是”1”,而是”一条指令占几个编址单位”。 教材写 时,那个 1 是加了引号的,意思是”一个指令长度”。按字节编址时几乎一定不是 1。

指令必然从主存(或 Cache)取,但操作数不一定。 操作数可以在寄存器里、可以是立即数、可以在栈顶。“寻址”不等于”访存”——立即寻址和寄存器寻址都不访存。

寻址特征字段的位数是设计参数,不是每台机器都有。 定长格式的 RISC 常常靠操作码本身隐含寻址方式(LW 就是基址+位移,没有别的可能),根本不需要独立的寻址特征字段。

对照速查

指令寻址数据寻址
找的是什么下一条指令的地址操作数的地址
结果送到PC送去访存(或直接用)
有哪几种顺序、跳跃十种(见 4.2.2)
算法复用数据寻址的那十种——
概念一句话
形式地址 指令里写着的那几位,是原料
有效地址 EA算完之后操作数真正所在的地址
寻址方式从 到 EA 的那个函数
寻址特征字段 位 → 最多 种寻址方式
判断对错
顺序寻址就是 ❌(增量 = 指令字长 ÷ 编址单位)
跳跃寻址是一种数据寻址方式❌(是指令寻址的一种情形)
转移指令的目标地址有专门的计算方式❌(复用数据寻址方式)
形式地址就是操作数地址❌(只有直接寻址时才相等)
每种寻址方式都要访存❌(立即、寄存器寻址不访存)
执行转移指令时 PC 里是当前指令地址❌(已经是下一条的地址)

考点

  • 指令寻址(→PC)与数据寻址(→操作数)是两回事,但算法是同一套
  • 顺序寻址增量 指令字长编址单位,按字节编址时不是 1
  • 变长指令的 PC 增量要等译码后才确定
  • 跳跃寻址只是往 PC 塞一个非顺序值,塞完立刻恢复顺序寻址
  • 形式地址 是原料,有效地址 EA 是结果,寻址方式是二者之间的函数
  • 寻址特征 位 → 最多 种寻址方式
  • 地址翻译链有六层:符号 → 形式地址 → EA → 线性地址 → 物理地址 → Cache 划分 / 主存译码;跨层比较是本章一切混乱的来源

链接