014. Instruction lda

Extract the LDA instruction mechanism.

Lesson 14 of 356 · tests/chapter_01_cpu/test_014_instruction_lda.py

Files to update

emulator/cpu/instructions.py
emulator/cpu/cpu.py

Locations

instructions.lda
CPU.step, existing $A9 and $AD branches

Why this step exists

An instruction defines the state transition after an operand is available. LDA always stores a value in A and updates Z/N, regardless of how that value was addressed.

Complete example implementation

# emulator/cpu/instructions.py
def lda(cpu, value: int) -> None:
    cpu.a = value
    cpu._update_zero_and_negative_flags(value)


# emulator/cpu/cpu.py
from emulator.cpu.addressing_modes import absolute, immediate
from emulator.cpu.instructions import lda


class CPU:
    def step(self) -> None:
        opcode = self.fetch_byte()

        if opcode == 0xA9:
            return lda(self, immediate(self))

        if opcode == 0xAD:
            return lda(self, self.bus.read(absolute(self)))

        raise NotImplementedError(
            f"Opcode {opcode:02X} not implemented"
        )

Important boundaries

  • immediate returns a value, while absolute returns an address to dereference
  • CPU.step selects the addressing mode
  • lda changes CPU state and flags

Common misconception

lda should not fetch instruction bytes. If it did, instruction behavior would become coupled to one addressing mode.

Out of scope

  • zero-page LDA
  • opcode-handler functions and OPCODE_TABLE
  • other load instructions

Run this lesson

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