Картридж, мапперы и тайл-движки
Механизм
Одна сквозная идея: адресуй больше, чем можешь держать — через фиксированное окно и таблицу переадресации. Сначала проблема, потом четыре её следствия.
Стена адресного пространства
У 6502 шина адреса 16 бит. Сколько разных адресов он вообще может назвать:
И это весь мир процессора: туда же ложатся RAM, регистры PPU и APU, ввод. На программный ROM картриджа отведено окно $8000–$FFFF — 32 КБ. Игра на 512 КБ физически не помещается в то, что CPU способен назвать одним адресом. Простой ROM (NROM, как у первого Super Mario Bros) и не пытается: он умещается в 32 КБ кода + 8 КБ графики, и точка. Чтобы расти, нужен трюк.
Bank switching — маппер как librarian
Картридж несёт собственный чип — маппер (Memory Management Controller, MMC). У него есть регистр банка. Игра записывает в него номер, и маппер перекоммутирует проводами, какой 16-КБ кусок физического ROM виден сейчас в окне $8000. Сколько банков в игре на 512 КБ при окне 16 КБ:
Книга на десятки глав, но стол — на одну: librarian (маппер) подкладывает нужную главу в окно по требованию. Тот же приём отдельно для графики: CHR-banking листает страницы pattern table (наборы плиток/спрайтов), поэтому анимации и тайлсеты тоже перестают упираться в 8 КБ.
Маппер участвует в рендере: scanline-IRQ
Поздние мапперы делали больше, чем листали страницы. MMC3 добавил счётчик строк развёртки: он подсматривает за линией A12 на шине PPU (она переключается по фиксированному паттерну, пока PPU тянет плитки каждую строку), считает строки и в выбранной дёргает IRQ процессора. Зачем: разрезать кадр. Прокручиваешь игровое поле сверху, а на середине экрана ловишь IRQ и фиксируешь нижнюю полосу — статус-бар (счёт, жизни) стоит как вкопанный, пока мир скроллится. Super Mario Bros 3 этим и живёт. Картридж тут — не хранилище, а активный соавтор кадра.
16-битный скачок и слои
Genesis и SNES расширили шину и память — и адресного пространства, и видеопамяти стало кратно больше. Сравнение поколения (числа сверены):
| Параметр | NES (1983) | Genesis (1988) | SNES (1990) |
|---|---|---|---|
| CPU | 6502 @ 1.79 МГц | 68000 @ 7.67 МГц | 65C816 @ 3.58 МГц |
| RAM (work) | 2 КБ | 64 КБ | 128 КБ |
| Палитра / на экране | 56 / 25 | 512 / 61 | 32768 / 256 |
| Фоновые слои | 1 | 2 | до 4 |
| Картридж | 32–512 КБ | 256 КБ–5 МБ | 256 КБ–6 МБ |
Главное здесь не «больше мегагерц», а несколько независимых фоновых слоёв. В m01 экран был одной тайловой картой (nametable). Теперь их несколько, у каждого свой регистр прокрутки и приоритет относительно спрайтов. Дальний слой (небо/горы) скроллишь медленнее ближнего — и почти бесплатно получаешь параллакс, иллюзию глубины. Спрайты вкладываются между слоями по приоритету: герой за столбом, но перед стеной.
Числовой пример. MMC3 разрезает кадр scanline-IRQ. Видимых строк 240; ставим прерывание на строке 192 — верхние 192 строки прокручиваются (фон сдвигается каждый кадр), на 192-й IRQ обнуляет регистр прокрутки, и нижние 240 − 192 = 48 строк рисуются с нулевым сдвигом → статичный HUD высотой 48 px. Один счётчик на картридже разделил экран на «мир» и «приборную панель».
🕹 В какие игры поиграть — и что заметить
Один вопрос «как уместить большую игру в маленький процессор» — лесенка ответов: от «никак, влезли в 32 КБ» через мапперы и слои до «привезли на картридже целый GPU». По каждому: как сделано и что включить/заметить.
Влез без банкинга: 32 КБ кода + 8 КБ CHR. Поэтому мир построен на жёстком переиспользовании одного набора плиток (куст = облако, перекрашенные палитрой) — банков нет, тайлсет один на всю игру. Это потолок «без маппера» во плоти.
🎮 Сыграй: в SMB замечай, как мало уникальных плиток и как агрессивно они повторяются между мирами. Это не стиль ради стиля — это 8 КБ CHR без подкачки.
MMC3 даёт тонкий банкинг (8-КБ страницы) и счётчик строк. SMB3 им режет кадр: верх скроллится, нижняя полоса-HUD стоит намертво. Mega Man листает CHR-банки ради анимации боссов и больших тайлсетов уровней. Игра внезапно «большая», хотя процессор тот же.
🎮 Сыграй: в SMB3 смотри на нижнюю панель (предметы/время): мир за ней едет, она — нет. Это IRQ маппера на конкретной строке. В эмуляторе с дебаггером увидишь точную строку прерывания.
16-битный 68000 быстрее и с DMA толкает больше пикселей: высокая скорость скролла + два фоновых плана с параллаксом. Маркетинговое «blast processing» — это и есть «процессор быстрее, DMA шире», никакого тайного граф-чипа. Реальный эффект, выдуманное имя.
🎮 Сыграй: в Sonic на скорости гляди на задний план — он ползёт медленнее переднего (параллакс из двух плоскостей). Сравни ощущение скорости с NES-играми: разница — это шире шина и DMA, а не магия.
Предел идеи: маппер мало — положим на картридж целый процессор. SuperFX (GSU) от Argonaut — RISC-ускоритель, рисующий 3D-полигоны в свой кадровый буфер; SNES сам так не умеет. Картридж перестаёт быть памятью и становится железом-ускорителем, едущим вместе с игрой (так же SA-1, DSP, Cx4 в других играх).
🎮 Сыграй: запусти Star Fox — это «3D» на машине без 3D, потому что чип внутри картриджа. Сравни плавность с Mode-7-играми (F-Zero) на голом SNES: там аффинный трюк, тут — настоящие полигоны от привезённого GPU.
Хардкор · инженерия: почему окно фиксировано, а вектор прерываний — нетможно пропустить
Bank switching выглядит магией, пока не спросишь: а из какого банка исполняется код, который меняет банк?
Фиксированный банк — это «трамплин»
У MMC1 окно $8000–$BFFF переключаемое, а $C000–$FFFF жёстко прибито к последнему банку. Туда кладут: вектора reset/IRQ/NMI (они физически в $FFFA–$FFFF), процедуру смены банка и общий «диспетчер». Нельзя выдёргивать половицу, на которой стоишь: код, переключающий банк, обязан жить в немигрирующей части. Поэтому вызов «функции из банка 7» — это: записать 7 в регистр (находясь в фиксированном банке) → прыгнуть в окно. Ровно как trampoline/PLT в динамической линковке.
Откуда чип на картридже знает про строку развёртки
MMC3 не видит ТВ. Он слушает линию A12 шины PPU. Пока PPU рисует строку, он лезет в pattern table по адресам, где A12 предсказуемо щёлкает; маппер ловит фронты A12, фильтрует дребезг (низкий уровень в течение трёх спадов M2) и считает их как строки. То есть картридж подслушивает адресную шину видеочипа и реконструирует тайминг, к которому формально не подключён. Хрупко (зависит от паттерна обращений PPU), но работает.
Почему не «просто больше адресных линий»
Расширить шину 6502 до 24 бит нельзя — она часть ISA процессора, который в каждой консоли уже впаян. Менять можно только то, что на картридже. Отсюда вся философия: ум выносится в сменное железо, неизменное ядро не трогаем. Это и есть граница «платформа против расширения».
Хардкор · теория: bank switching = пейджинг, и где он ломаетсяможно пропустить
Регистр банка — это одна запись таблицы страниц: logical address → physical frame. Разница с настоящим MMU — в гранулярности и прозрачности.
Гранулярность
MMU процессора разбивает всё адресное пространство на страницы (4 КБ) с таблицей на сотни записей; маппер даёт 1–4 переключаемых окна по 8–16 КБ. Это «пейджинг для бедных»: меньше окон, грубее куски, но идея тождественна.
Прозрачность и кто отвечает за промах
В ОС промах страницы (page fault) ловит железо и прозрачно подгружает страницу — программа не знает. На NES прозрачности нет: сам код обязан знать, что нужный кусок не в окне, и явно переключить банк. Это ближе к overlay-системам мейнфреймов (ручная подкачка оверлеев), чем к demand paging. Цена ошибки — прыжок в чужой банк и краш; отладка таких багов на железе 80-х была адом.
Стоимость переключения
MMC1 принимает команду серийно — 5 записей со сдвигом на команду; MMC3 — 2 записи (быстрее). Частый банк-свич в горячем цикле дорог, поэтому раскладка кода по банкам — это оптимизация локальности: что вызывается вместе, держи в одном банке. Прямой предок «cache locality» и data-oriented раскладки (см. ECS).
ОС / системы: bank switching — это виртуальная память и пейджинг в чистом виде: регистр банка = запись таблицы страниц, банк = physical frame, окно $8000 = страница виртуального адреса. Оверлеи мейнфреймов, mmap, своп, сегменты x86 real-mode — родня. CHR-banking ⇄ стриминг текстур из дальнего хранилища в видеопамять по требованию.
ML / AI (твой домен): vLLM PagedAttention — дословно bank switching для KV-кэша: логическая block-table проецирует последовательность на разбросанные физические блоки GPU-памяти, фрагментация падает с 60–80% до <4%. Model offloading / ZeRO-Offload — пейджинг весов диск→CPU→VRAM, когда модель не влезает в окно VRAM. Mixture-of-Experts — «подкачай нужного эксперта на токен» = CHR-banking для весов. А SuperFX = аппаратный ускоритель рядом с задачей: GPU/TPU/inference-чип — это «сопроцессор на картридже» для нейросети.
Бэкенд / данные: окно над большим стором — это пагинация запросов (LIMIT/OFFSET, курсоры), working-set кэши, CDN-edge как «банк», подкачиваемый из origin; indirection-таблица = слой адресации (consistent hashing, shard map).
Принцип: когда хранилище больше окна — не пытайся вместить всё; заведи маленькое окно и таблицу, что в нём сейчас лежит. А дорогую специальную работу выноси в ускоритель, едущий вместе с данными.
Если 6502 видит лишь 64 КБ, как игра вообще исполняет код во всех 512 КБ — всегда же есть кусок, недостижимый прямо сейчас?
MMC3 «считает строки развёртки» — как чип на картридже знает, что рисует ТВ, к которому не подключён?
A12. Пока PPU тянет данные плиток для очередной строки, A12 щёлкает по предсказуемому паттерну; маппер ловит её рост (после фильтра дребезга — низкий уровень три спада M2) и считает как строки. Формально маппер к видеовыходу не подключён — он реконструирует тайминг из обращений к памяти. Гениально и хрупко: зависит от того, как именно PPU ходит в pattern table.«Blast processing» у Genesis — это был реальный чип?
Раз картридж мог нести сопроцессор (SuperFX), почему не совали CPU в каждую игру?
CD-ROM давал сотни мегабайт дёшево — почему он не убил картридж сразу?
- NESdev Wiki — статьи MMC1, MMC3, Mapper: первоисточник по банкингу и scanline-IRQ.
- Super FX (Wikipedia) и «List of Super NES enhancement chips» — сопроцессоры на картриджах (SuperFX/SA-1/DSP).
- Nick Montfort & Ian Bogost, «Racing the Beam» — архитектурный контекст эпохи (NES-главы).
- Kwon et al., «Efficient Memory Management for LLM Serving with PagedAttention» (vLLM, 2023) — тот же приём в ML.
- Модуль 2, «Console Wars & Genre Crystallization» (
02-console-wars-1985-1993.md).