005. Memory interface

Introduce the common memory-device interface.

Lesson 5 of 356 · tests/chapter_01_cpu/test_005_memory_interface.py

File to create

emulator/memory/memory_device.py

File to update

emulator/memory/ram.py

Locations

class MemoryDevice
class RAM(MemoryDevice)

Why this step exists

CpuBus will soon route accesses to different devices. A small abstract interface lets the bus depend on read/write behavior instead of the concrete RAM representation.

Complete example implementation

# emulator/memory/memory_device.py
from abc import ABC, abstractmethod


class MemoryDevice(ABC):
    @abstractmethod
    def read(self, addr: int) -> int:
        ...

    @abstractmethod
    def write(self, addr: int, value: int) -> None:
        ...


# emulator/memory/ram.py
from dataclasses import dataclass, field

from emulator.memory.memory_device import MemoryDevice


@dataclass
class RAM(MemoryDevice):
    _data: bytearray = field(
        default_factory=lambda: bytearray(0x800),
        init=False,
    )

    def read(self, addr: int) -> int:
        return self._data[addr]

    def write(self, addr: int, value: int) -> None:
        self._data[addr] = value

Important invariant

MemoryDevice defines the operations but does not own storage or address mapping.

Common misconception

An abstract base class does not make RAM contents abstract. RAM still owns concrete byte storage; only its callable boundary is shared.

Out of scope

  • FakeROM, introduced in Test 006
  • program-ROM bus mapping
  • read-only cartridge behavior

Run this lesson

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