020. Lda 先变址后间接寻址

添加先变址后间接寻址的 LDA($A1,写作 `(d,X)`)。

20 / 356 · tests/chapter_01_cpu/test_020_LDA_indirect_x.py

要更新的文件

emulator/cpu/addressing_modes.py
emulator/cpu/opcodes.py

位置

addressing_modes.indirect_x
opcodes.lda_indirect_x
opcodes.OPCODE_TABLE[$A1]

为什么需要这一步

先变址后间接寻址将操作数与 X 相加,用于在零页中选出一个两字节指针。该指针随后给出 LDA 所加载值的最终 16 位地址。

完整示例实现

# emulator/cpu/addressing_modes.py
def indirect_x(cpu) -> int:
    operand = cpu.fetch_byte()
    pointer = (operand + cpu.x) & 0xFF

    low = cpu.bus.read(pointer)
    high = cpu.bus.read((pointer + 1) & 0xFF)

    return low | (high << 8)


# emulator/cpu/opcodes.py
from emulator.cpu.addressing_modes import indirect_x


def lda_indirect_x(cpu) -> None:
    address = indirect_x(cpu)
    lda(cpu, cpu.bus.read(address))


OPCODE_TABLE = {
    # Preserve existing entries.
    0xA1: lda_indirect_x,
}

A1 20 在 X=$04 时的地址时间线:

fetch operand $20
    -> pointer location $24
    -> read low byte from $0024
    -> read high byte from $0025
    -> assemble final address
    -> read value for LDA

重要不变量

  • 在读取指针之前先加上 X
  • 指针选择在零页内回绕
  • 从指针 $FF 读取高位字节时会回绕到 $00

常见误解

不要把 X 加到最终的 16 位地址上。那是另一种寻址机制;(d,X) 变址的是零页中的指针位置。

范围之外

  • 间接,Y,在测试 021 中引入
  • 跨页周期惩罚
  • JMP 特有的间接寻址行为

运行本课

uv run pytest tests/chapter_01_cpu/test_020_LDA_indirect_x.py -v