Мапперы 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 комментария
По части детального описания у меня только программирование под Game Boy Advance: antistupd.livejournal.com/842.html
Обожаю GBA, он его архитектура воплотила мою мечту из глубокого детства сделать игру с плавным скроллингом — и тогда я еще не знал даже сколь это тривиальная задача на консолях с тайловыми видеочипами.
Как раз с того же самого gamedev.ru :)
Ссылки в той же статье тоже есть. Поэтому можно самому компилировать и пробовать. Карты те же попробовать делать, ибо в этой роли используется свободный TileEd.
Главное чтобы Konami не выдвинуло правовых претензий. xD
Они реально очень разные и тут ты крут без сомнений. :)
1. исходники будут
2. можно будет что-то поменять незначительно, или переделать использование особенностей их vdp
посмотрим, уопщем. ты в курсе)
Немного подумал над этой идеей. Вернее решил сформулировать что там за VDP.
В целом — классика тайловых консолей. У тех режимов что я использую в GBA в этом проекте — до 4-х независимо прокручиваемых задних слоёв. Я сейчас использую два — один для «фона неба», другой для карты. Классическое «проворачивание» с обновлением краевых полосок для иллюзии бесконечного скроллинга делает PPU. Но работа по обновлению этих фонов происходит в строго локализованном месте и конечно может быть полностью переписана. В крайнем случае можно фон неба вообще вписать в фон карты оставив один скроллящийся фон как это было собственно в денди — там не было параллакса, это собственно моё нововведение в порте.
Второе — спрайты. Тоже классические. Работа с ними тоже строго локализована и каждый кадр строится заново список спрайтов через beginSpriteDraw/drawSprite/endSpriteDraw. То есть можно тоже переделать легко под блиттинговый принцип.
Палитр две 8-битных для фонов и спрайтов отдельно, то есть цвет пикселя задаётся байтом. Но в режиме оригинальной цветности можно свести в одну 8-битную палитру. Всего же у денди меньше чем 64 вообще возможных цветов.
Единственное еще что вызывает вопрос — под GBA есть новый и сравнительно модный GCC, который и использую, с поддержкой C++14. А такое есть под Z80? Потому что некоторые фичи последнего действительно используются.
По игре: два задних фона полностью устраивают, имеем два тайловых слоя.
Цветов 256, на фон может уйти от 15 до 60 (4 палитры из доступных 16ти, нулевой цвет прозрачность)
Спрайты у нас есть, в 15 цветов.
К слову, у этого пути есть побочные эффекты — если расположить спрайты и тайлы в одном окне PPU (т.е. настроить PPU, чтобы он брал и тайлы и спрайты из одной страницы), прерывания перестанут работать. Ну и если выключить рендер, прерывания тоже перестанут приходить, а значит, скрывать артефакты доступа к видеопамяти во время хода луча по кадру становится сильно сложнее — гасить экран обычно хочется на неопределённое время, но для нормальной работы прерываний ниже по кадру можно гасить только на фиксированное время.
К вопросу ограничений CNROM и UNROM. Большинство дискретных мапперов (на обычной мелкой логике), включая эти два, позже подвергались расширению китайцами и фанатами. Поэтому есть варианты CNROM на 128К, UNROM на 512К и 4096К, есть подобный UROM по сути маппер на 64M (защёлкиваются биты ША, а не ШД).