Мапперы Famicom/NES/Денди





Первые картриджи с играми Famicom/NES/Денди содержали два банка ПЗУ — графики и кода. Микросхема ПЗУ кода отображалась («маппилась») на последние 32 Кб адресного пространства центрального процессора, а микросхема с графическими данными отображалась на первые 8 Кб внутренней памяти видеочипа (Picture Processing Unit — PPU) и содержала набор тайлов игры в двух банках по 256 тайлов 8x8 каждый. Один из них использовался для плиток фона, а другой — для подвижных спрайтов. Вот так, например, выглядели банки графики игры Lode Runner (в эмуляторе FCEUX):



Кроме этого PPU содержал 2 Кб видеоОЗУ (VRAM) в который влезало примерно два экрана изображения фона, что использовалось для организации плавной прокрутки. Например в той же Lode Runner поле в видеопамяти выглядело так:



Как видно ширина игровых карт диктовалась как раз размерами видеопамяти — это позволяло динамически обновлять её содержимое, ОЗУ была в денди роскошью — еще 2 Кб было в адресном пространстве процессора и всё. Такими же размерами обладали поля еще в таких играх как Bomberman или Mappy — по схожим причинам. Однако довольно быстро 32 Кб на программу и 8 Кб на графику перестало хватать и в картриджи денди стали встраить так называемые «мапперы» — микросхемы переключающие банки памяти на лету и делающие возможным использование гораздо больших объёмов графики и кода (но не одновременно).
Разных мапперов было создано сотни разных видов и, возможно, до сих пор делаются новые.
Каких то стандартов особо нет — любой желающий может сделать чип, если его не устраивают присутствующие на рынке, расширив каким то образом функционал консоли.Однако некоторые виды мапперов распространены чаще других. Создатели эмуляторов пронумеровали их по сути выделив первые номера самым часто используемым.
Из документации EveryNES можно почерпнуть следующее распределение по типам:

Тип                 Игр   Процент
Mapper 0 (NROM)     446   12.5%
Mapper 1 (MMC1)     723   20.3%
Mapper 2 (UNROM)    397   11.2%
Mapper 3 (CNROM)    273    7.7%
Mapper 4 (MMC3)     784   22.1%
Другие              932   26.2%
Всего               3555 100.0%

Нулевой Mapper 0 (NROM) это «без маппера» — простое отображение неизменяемых кусков ПЗУ картриджа в 8Кб банков тайлов и верхние 32Кб процессора.
Здесь важно еще заметить, что визуальное расположение двух видеостраниц можно было переключать между горизонтальным и вертикальным режимами скроллинга. Так вот на самом деле это делалось через картридж. В обычной распайке две имеющихся страницы компоновались горизонтально, а чтобы они стали вертикальными надо было перекоммутировать 2 адресных линии памяти видеоадаптера. Делалось это через картридж и без всяких мапперов в игру можно было «запаять намертво» один из этих режимов. Естественно в таких играх как «Черный плащ», где тип скроллинга менялся в некоторых местах на другой нужна была управляемая перекоммутация этих линий и за это в итоге тоже отвечали мапперы.
Итак, какие проблемы решали самые распространённые виды мапперов (мало значимые детали будут опущены):

Mapper 1 — MMC1
(применялся в таких играх как Legend of Zelda, Metroid, Rad Racer, Mega Man 2 и многих других)
Первое — с ним можно управлять режимом вертикального или горизонтального скроллинга.
Но самое главное, что он довольно прямолинейно и гибко решает первую возникшую при росте аппетитов игр проблему — нехватку памяти для прямой адресации как процессором так и видеочипом.
Если вкратце, то позволяет подменять отображение ПЗУ картриджа как в каждым из двух банков тайлов (по отдельности, но целиком, т.е. страницами по 4Кб), так и первую страницу в 16Кб в ПЗУ процессора (последние 16Кб ПЗУ процессора всегда отображаются в одну и ту же микросхему ПЗУ на картридже).
Это позволяло содержать в верхних 16Кб ПЗУ некое «ядро игры» и при этом налету подменять каждый из банков тайлов для графики и 16Кб кода и/или данных для каждого уровня.

Mapper 2 — UNROM
(применялся в таких играх как Castlevania, Mega Man, Ghosts & Goblins, Amagon и многих других)
Так же как и MMC1 способен переключать первые 16Кб ПЗУ процессора в то время как последние 16Кб не переключаются и составляют «ядро игры».
Но вот с банками тайлов этот маппер поступает хитрее — вместо переключения отображения в разные микросхемы ПЗУ он отображает на оба банка памяти микросхему ОЗУ.
Таким образом изображения тайлов могут гибко налету заменяться другими не всем банком целиком, а как угодно.
В самом деле, если вы присмотритесь к карте спрайтов из игры Lode Runner, то заметите, что она на 2/3 занята анимациями всего 2–ух типов «человечков» — собственно игрока и преследующих его «бомберменов».
Действительно 256 тайлов 8x8 очень мало для отрисовки разнообразных персонажей, даже учитывая, что спрайты имеют флажки вертикального и горизонтального зеркалирования (что сильно экономит играм байты).
В реальных играх либо видов монстров одновременно присутствующих на одном уровне или очень немного или банк тайлов спрайтов подменяется на лету. Но т.к. в MMC1 банк можно было заменить только целиком, такое приводило бы к перерасходу ПЗУ на одинаковые изображения главного героя, поэтому посадить банки тайлов на ОЗУ и обновлять их по строгой необходимости, когда один вид монстра покидает экран, а другой появляется, выглядит крайне разумной идеей.
Тем более, что в самой консоли не было столько ОЗУ — 2Кб у процессора плюс 2Кб у видеочипа (+мелочь на спрайты и палитру) вдвое меньше этого объёма.

Mapper 3 — CNROM
(применялся в таких играх как Solomon's Key, Gradius, Cybernoid, Adventure Island и многих других)
Самый «ограниченный» из всех перечисленных — мог только переключать сразу оба банка тайлов на одну из четырёх возможных страниц ПЗУ по 8Кб.

Mapper 4 — MMC3
(самый навороченный из массовых, вошёл в широкое употребление в начале 90–х. Применялся в таких играх как Super Mario Bros. 2 и 3, Mega Man 3, 4, 5, и 6, Crystalis и многих других)
Мог управлять вертикальным/горизонтальным скроллингом.
Мог переключать маппинг ПЗУ банков тайлов с гранулярностью в 1Кб, что было компромиссом между проблемами MMC1 и дороговизной UNROM.
Мог переключать маппинг ПЗУ процессора с гранулярностью в 8Кб — получалось 2 переключаемых страницы в начале и 2 непереключаемых в конце ПЗУ.
Мог маппить постоянное ОЗУ (SRAM=Static RAM, обычно на батарейках) для сохранения игр в адреса 6000h–7FFFh и имел бит защиты этой области от записи.
Имел встроенный счётчик отрисованных в текущем видеокадре строк и мог генерировать прерывание по достижению заданного значения.
Последнее жизненно важно для сложных вариантов многократных HBlank–отсечений. Дело в том, что опять таки, без апгрейдов консоль могла делать только одно HBlank–отсечение (смену фона по горизонтальной границе на экране — тема для отдельного поста) техникой так называемого «zero–sprite–hit». Нулевой спрайт имел особую фичу — когда видеочип отрисовывал первый видимый пиксель нулевого спрайта поверх видимого пикселя фона, то он взводил одноименный флаг в одном из своих портов ввода–вывода — «zero–sprite–hit». Вот за этот флаг мог зацепится процессор, чтобы поймать момент отрисовки определенной строки пикселей и далее уже действовать по обстоятельствам. Однако сделать это он мог только один раз за кадр — во время отрисовки кадра CPU не может иметь доступ к памяти видеочипа — включая память спрайтов, даже во время HBlank, поэтому передвинуть нулевой спрайт для другого HBlank–отсечения уже не было никакой возможности.
Вот здесь и приходил на помощь маппер MMC3 — встроенный счётчик вертикальных линий позволял организовать при должной сноровке сколько угодно HBlank–отсечений за кадр — и этим игры с удовольствием пользовались. В такой игре как Gun Dec (он же Vice) на первом платформерном уровне присутствовала полоска «колыхающейся» воды — в ней каждая горизонтальная линия «плыла» отдельно от других, порождая эффект колыхающейся воды. Без маппера подобного MMC3 такое было бы невозможно сделать, особенно с учетом того, что там еще не раз делается HBlank–отсечение.
Забавно еще то как именно был реализован этот счётчик отрисованных сканлайнов — видеочип не проектировался для такого и пришлось найти изощрённый обходной путь. Во время построения кадра PPU многократно обращается к видеопамяти и было замечено, что он переключается между обращениями к банкам тайлов и видеостраницам ровно 42 раза за один сканлайн. Это и навело инженеров на необходимую технику — чип MMC3 отслеживал изменение адресной шины A13 видеочипа, которая как раз взводилась только при доступе к находящимся в верхних адресах памяти видеостраницам, и по счётчику понимал когда происходит переход к следующей строке. Замысловато, но нужный результат достигался.
Маппер MMC3 получился удачным и дал жизнь многим производным чипам — в каких то урезался ненужный функционал, но в большинстве добавлялись новые фички.
Так же нужно понимать, что по части основного функционала — отображения адресного пространства CPU и PPU на чипы картриджа, мапперу по сути неважно микросхема ПЗУ или ОЗУ в картридже установлена. Поэтому не меняя сам маппер можно было получить картридж, где опять таки на месте банков тайлов находится ОЗУ VRAM с картриджа. Возможны были самые разнообразные комбинации, разного состава и размеров запоминающих устройств.

Прочих видов мапперов было сотни, но все остальные не применялись больше, чем в 2% игр каждый, а нередко и всего в одной–двух.
Однако нельзя тут не упомянуть такого монстра, которого Nintendo выпустила уже под закат консоли, как маппер 5 или MMC5. Хотя он использовался не более чем в полутора десятках игр, но его начинка была уж совсем неприличной:

Mapper 5 — MMC5
(использовался в таких играх как Gun Sight (Laser Invasion), Uchuu Keibitai SDF, Bandit Kings (Suikoden), Castlevania 3, Nobunaga Sengoku (Nobunaga's Ambition 2), Nobunaga Bushou, Shin 4 Nin Uchi Mahjong, Ishin no Arashi, L'Empereur, Ganbare Goemon Gaiden, Romance of the Three Kingdoms 2 (Sangokushi 2), Gemfire (Royal Blood), Uncharted Waters (Daikoukai Jidai), Aoki Ookami, Just Breed, Metal Slader Glory)
Помимо гибких режимов отображения страниц этот маппер так же мог:
— счетчик отрисованных сканлайнов с генерацией прерываний по HBlank
— адресовать до 64Кб ОЗУ, которое мог замапить не только в адреса $6000–$7FFF, но и в $8000–$DFFF
— аппаратно умножать байт на байт с получением 16–битного результата
— два дополнительных звуковых осциллятора (работали параллельно с уже имеющимися в консоли) и 8–битный PCM–канал
— режим «заливки видеостраниц», полезный в «переходных экранах»
— 1024 байта ОЗУ которые можно использовать для одного из четырёх вариантов:
а) дополнительная видеостраница
б) расширитель атрибутов и тайловых индексов — позволяет видеочипу адресовать сразу 16384 тайлов фона одновременно и позволяет каждому тайлу фона иметь индивидуальный селектор палитры
в) вертикальный сплит–скрин
г) дополнительное ОЗУ для процессора

В общем этот маппер некисло так расширял аппаратную начинку консоли, вплоть до графических и звуковых возможностей, по сути являясь уже полноценным expansion pack–ом.

Так что та же эмуляция Денди/NES/Famicom просто невозможна по большому счёту без эмуляции маппера в картридже ибо сами картриджи в большинстве своём содержали заметно больше, чем просто переключатели банков памяти.
Да и сама возможность переключать банки памяти не закладывалась в консоль, как и многое другое.

23 комментария

avatar
Было на gamedev.ru год назад, но спасибо за напоминание.
avatar
О, какой аккаунт там? Это я и есть =A=L=X= и та тема моя и есть.
avatar
Да-да, именно этот. Вот бы с месяцок назад этот топик, я как раз копался с анромом.
avatar
Если прям именно разбираться, то мои обзоры не подходят, надо прямо в источниках как правило англоязычных смотреть. У меня обычно просто обзорные компиляции поверхностных сведений, чтобы на принципиальном уровне понять что там внутри происходит.
По части детального описания у меня только программирование под Game Boy Advance: antistupd.livejournal.com/842.html
avatar
Любая инфа хороша, особенно если на родном языке, что упрощает восприятие. ЖЖ ссылочку пометил звездочкой, раньше баловался GBA кодингом, и, возможно, ещё вернусь к нему.
avatar
Я затеял проект по продолжению 8-битной Contra Force с фамикома на Game Boy Advance, но пока уже несколько месяце времени нет особо. Но человечки уже бегают, прыгают и лифты ездят: youtu.be/FwRUjuW54aE
Обожаю GBA, он его архитектура воплотила мою мечту из глубокого детства сделать игру с плавным скроллингом — и тогда я еще не знал даже сколь это тривиальная задача на консолях с тайловыми видеочипами.
avatar
Вот это новость, т.е., возможно, мы скоро будем играть в нетормозящую КФ и на GBA? Это здорово.
avatar
:) Я это затеял как практикум для вышеупомянутых уроков по программированию под GBA и всё доступно для скачивания от ресурсов до исходного кода: gamedev.ru/flame/forum/?id=227447
Как раз с того же самого gamedev.ru :)
Ссылки в той же статье тоже есть. Поэтому можно самому компилировать и пробовать. Карты те же попробовать делать, ибо в этой роли используется свободный TileEd.
Главное чтобы Konami не выдвинуло правовых претензий. xD
avatar
а потом можно будет её на конфу перенести :)
avatar
Вот насчёт переноса с одной платформы на другую — тут ты несомненно круче всех моих начинаний. :)
Они реально очень разные и тут ты крут без сомнений. :)
avatar
Находи время и доделывай, займёмся.
avatar
GBA != GBC, мэн, это будет не просто.
avatar
дыкъ
1. исходники будут
2. можно будет что-то поменять незначительно, или переделать использование особенностей их vdp

посмотрим, уопщем. ты в курсе)
avatar
Я всегда за, если что)
avatar
«или переделать использование особенностей их vdp»

Немного подумал над этой идеей. Вернее решил сформулировать что там за VDP.
В целом — классика тайловых консолей. У тех режимов что я использую в GBA в этом проекте — до 4-х независимо прокручиваемых задних слоёв. Я сейчас использую два — один для «фона неба», другой для карты. Классическое «проворачивание» с обновлением краевых полосок для иллюзии бесконечного скроллинга делает PPU. Но работа по обновлению этих фонов происходит в строго локализованном месте и конечно может быть полностью переписана. В крайнем случае можно фон неба вообще вписать в фон карты оставив один скроллящийся фон как это было собственно в денди — там не было параллакса, это собственно моё нововведение в порте.
Второе — спрайты. Тоже классические. Работа с ними тоже строго локализована и каждый кадр строится заново список спрайтов через beginSpriteDraw/drawSprite/endSpriteDraw. То есть можно тоже переделать легко под блиттинговый принцип.
Палитр две 8-битных для фонов и спрайтов отдельно, то есть цвет пикселя задаётся байтом. Но в режиме оригинальной цветности можно свести в одну 8-битную палитру. Всего же у денди меньше чем 64 вообще возможных цветов.
avatar
P.S.
Единственное еще что вызывает вопрос — под GBA есть новый и сравнительно модный GCC, который и использую, с поддержкой C++14. А такое есть под Z80? Потому что некоторые фичи последнего действительно используются.
avatar
Надо попробовать компиляцию в sdcc, под з80

По игре: два задних фона полностью устраивают, имеем два тайловых слоя.
Цветов 256, на фон может уйти от 15 до 60 (4 палитры из доступных 16ти, нулевой цвет прозрачность)
Спрайты у нас есть, в 15 цветов.
avatar
aa-dav а вот интресно как с Mapper 5 — MMC5 выводился этот дполнительный звук?
  • Nuts_
  • +1
avatar
походу, этот звук шел на коннектор катриджа но дажлеко не все консоли могли этот звук принять и подмиксовать с основным
avatar
Именно так, все чипы с дополнительным звуком выводили его на специальный контакт слота картриджа, и в приставке он смешивался с основным. Но это только в Famicom, в NES он не подключен, в клонах — как повезёт. Плюс ещё есть традиционная проблема баланса громкости встроенного и внешних чипов (аналогично MSX).
avatar
Да, поэтому ретрогеймеры все знают, что у американской версии Castlevania 3 отвратный звук по сравнению с японкой, вот на ютубе можно убедиться в сравнении: www.youtube.com/watch?v=Rh-vkpjyMTw
avatar
По мапперам я давеча начал объёмную статью, в продолжение тематических постов здесь, но она так и лежит в ожидании своего часа.

Забавно еще то как именно был реализован этот счётчик отрисованных сканлайнов — видеочип не проектировался для такого и пришлось найти изощрённый обходной путь.
К слову, у этого пути есть побочные эффекты — если расположить спрайты и тайлы в одном окне PPU (т.е. настроить PPU, чтобы он брал и тайлы и спрайты из одной страницы), прерывания перестанут работать. Ну и если выключить рендер, прерывания тоже перестанут приходить, а значит, скрывать артефакты доступа к видеопамяти во время хода луча по кадру становится сильно сложнее — гасить экран обычно хочется на неопределённое время, но для нормальной работы прерываний ниже по кадру можно гасить только на фиксированное время.

К вопросу ограничений CNROM и UNROM. Большинство дискретных мапперов (на обычной мелкой логике), включая эти два, позже подвергались расширению китайцами и фанатами. Поэтому есть варианты CNROM на 128К, UNROM на 512К и 4096К, есть подобный UROM по сути маппер на 64M (защёлкиваются биты ША, а не ШД).
  • Shiru
  • +2
avatar
Спасибо, очень познавательно и просто расписано. По-другому теперь взглянул на многие эффекты в играх на NES.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.