216. Разбор iNES ROM

добавьте

Урок 216 из 356 · tests/chapter_02_rom_loading/test_216_parse_ines_rom.py

добавьте emulator/cartridge/ines.py::parse_ines_rom.

Зачем нужен этот шаг

Эта функция превращает заявленные заголовком значения в чистые срезы PRG/CHR, так что последующему коду Cartridge и mapper никогда не нужно понимать заголовки iNES или смещения trainer. Она использует все константы формата и модели парсера из уроков 212-215.

Предлагаемая реализация

def parse_ines_rom(data: bytes) -> INesRom:
    header = parse_ines_header(data)
    prg_size = header.prg_rom_banks * PRG_ROM_BANK_SIZE
    chr_size = header.chr_rom_banks * CHR_ROM_BANK_SIZE
    prg_start = INES_HEADER_SIZE + (
        TRAINER_SIZE if header.has_trainer else 0
    )
    prg_end = prg_start + prg_size
    chr_start = prg_end
    chr_end = chr_start + chr_size
    if len(data) < chr_end:
        raise ValueError(
            "iNES data is too short for declared PRG/CHR ROM"
        )
    return INesRom(
        header=header,
        prg_rom=data[prg_start:prg_end],
        chr_rom=data[chr_start:chr_end],
    )

Инварианты: размеры берутся из количества банков; PRG начинается после заголовка и опционального 512-байтового trainer; CHR идёт сразу за PRG; все заявленные байты должны существовать перед выполнением среза. Не полагайтесь на снисходительные короткие срезы Python, которые молча примут усечённый образ.

Вне рамок этого шага

1. Extra trailing-byte policy and CHR RAM allocation are not introduced here.
2. Lesson 217 constructs a `Cartridge` from this parser result.
3. Lessons 218-220 add mapper behavior and mapper selection.

Запустить этот урок

uv run pytest tests/chapter_02_rom_loading/test_216_parse_ines_rom.py -v