=A=L=X=
> Это тоже достаточно сомнительное утверждение. Смотря для чего.
Для вывода графики. Если брать соотношение возможностей / цены железа
innuendo
> Если брать соотношение возможностей / цены железа
Я про это сразу написал.
Архитектура памяти в NES/Dendy
Пришло время написать про тот кавардак, который творился на денди с так называемыми "мапперами".
Но для начала немного об архитектуре памяти в денди/NES/Famicom.
Основными устройствами консоли являются центральный процессор (CPU) и видеочип (PPU, Picture Processing Unit). Каждое из них обладает собственным адресным пространством.
16-битное адресное пространство CPU общим объёмом 65536 байт разбито на две равных части. В первой с адреса 0 находятся 2 (всего два!) встроенных килобайта оперативной памяти консоли и порты ввода-ввода. Таким образом большая часть этого пространства образует неиспользуемые "дыры" и некоторые картриджи могут замапить в них до 8Кб дополнительного ОЗУ или энергонезависимой памяти, но это была сравнительно редкая практика. Большинство игр обходилось встроенными 2Кб оперативной памяти для хранения всех переменных, поэтому почти во всех играх монстры "бесконечно респавнятся" в том или ином виде - памяти чтобы хранить состояние их на всём уровне просто не хватало.
Вторая половина адресного пространства CPU - последние 32Кб памяти мапится на микросхемы картриджа, в подавляющем большинстве случаев - ПЗУ с кодом и данными игр. Надо заметить, что процессор 6502 при включении или после сброса стартует как раз с адреса считываемого из слова в памяти по адресу 0xFFFC, поэтому, если картридж содержит меньше, чем 32Кб памяти программы и данных, то они мапятся в последние адреса.
Видеочип (PPU) был довольно замысловатым девайсом, с замысловатой программой поведения и собственным адресным пространством, ПЗУ и ОЗУ - самый настоящий аппаратный ускоритель 2D-графики.
Минимальной порцией изображения у него был тайл 8x8 пикселей. Каждый тайл был 4-х-цветным, т.е. требовалось 2 бита на пиксель, поэтому изображение одного тайла требовало 8x2x8=128 бит или 16 байт. В начале адресного пространства PPU располагалось 2 банка тайлов по 256 тайлов в каждом. Таким образом каждый банк имел размер 256*16=4Кб, а вместе они занимали первые 8Кб памяти PPU. При типовом использовании один банк тайлов использовался при выводе фона, а другой - при выводе спрайтов. Обычно, особенно в первых видеоиграх, в банки тайлов отображалось ПЗУ картриджа. Здесь, как говорится, лучше 1 раз увидеть. Вот так, для примера, выглядит содержимое банков тайлов в игре Lode Runner (в эмуляторе):
Здесь видно, что первый банк отведен под спрайты, а второй под фон, шрифт и логотип игры в главном меню.
Следующие 4Кб видеопамяти (с адреса 8192) были зарезервированы под ОЗУ четырёх видеостраниц фона, но, как я уже говорил в первопосте, только первые 2Кб этого ОЗУ были установлены в самой консоли. Видеостраницы содержат массивы (в документации они называются name tables) байт 32x30, каждый из которых содержал индекс тайла (0-255) из банка тайлов, назначенного на банк фонов. В экран максимум могло влезть как раз 32x30 тайлов, т.е. 256x240 пикселей.
Как понятно, всего на фоне одновременно "честным образом" могло быть отображено только 256 разных по содержанию тайла. Всего же экран был замощен 960 тайлами, то есть большая часть из них была обречена повторяться! Это создавало большой вызов даже при выводе красивых заставок в начале игры.
Вот здесь: http://hypr.ru/blog/graphics/283.html есть отличная статья на тему того какими ухищрениями занимались создатели видеоигр для денди для этого дела. Частично там затронута и тема мапперов.
Последние 64 байта в каждой видеостранице содержали двухбитовые селекторы палитр для блоков 2x2 тайлов фона, таким образом добивая суммарный объём видеостраницы до ровно килобайта - 1024 байт. Я ни разу не замечал этого в детстве, столь хорошо в играх это скрадывалось, но в наши дни, уже зная последнее, стал замечать, что блоки тайлов 2x2 заднего фона не могут иметь разную палитру.
Помимо всего этого PPU имело так же 256 байт памяти для описания спрайтов (4 байта на спрайт давало 64 аппаратных спрайта) и еще немного для палитры и некоторых глобальных параметров.
CPU не имел прямого доступа к видеопамяти, дотянуться до неё он мог только во время VBlank (потому что в любое другое время PPU на 100% блокировал свою шину видеопамяти запросами) и только через порты ввода-вывода. В одном порте выставлялся адрес видеопамяти, а в другой шла запись или из него производилось считывание байта. Процесс был не особо шустрый, поэтому вопрос "как сделать скроллинг и при этом поменьше лазить в видеопамять" стоял довольно остро.
Именно для его решения и было несколько видеостраниц - при скроллинге за границы одной становились видны другие, повторяясь циклически (см. первопост). При должной сноровке можно было сделать бесконечный скроллинг по вертикали или горизонтали с обновлением только одной строки (или столбца) тайлов на каждые 8 пикселей. Но, как я уже говорил, в связи с тем, что в самой консоли было установлено только 2Кб видеоRAM для двух видеостраниц, то скроллинг в произвольном направлении становился чуть ли не невозможен без доработок на картридже.
Я позаимствую тут анимированную иллюстрацию этого с статьи на английском языке:
Здесь шестнадцатеричными числами 0x2000 и 0x2400 как раз помечены первая и вторая видеостраницы. Так же можно заметить, что заливка новых столбцов происходит порциями по 2 столбца за раз - это связано как раз с тем, что атрибут селектора палитры в видеостраницах задаются для блоков 2x2 тайла, поэтому оперировать такими блоками проще. Заметьте так же, что в момент пересечения правой границы правой видеостраницы отображение зацикливается на первую - таким образом можно создать иллюзию сколь угодно долгой прокрутки, само же изображение "циклически замкнуто" в двух страницах. И вот для того чтобы скроллить произвольно в любом направлении нужны как раз 4 видеостраницы.
Первому поколению видеоигр на денди (например танчики, Popeye или Pac-Man) с лихвой хватало одной или двух видеостраниц, 256 тайлов фона и 256 тайлов спрайтов. Фактически картридж содержал 2 микросхемы ПЗУ - 8 Кб для банков тайлов и от 16 до 32Кб для второй части адресного пространства CPU и они просто заводились в систему практически "напрямую". (образы таких игр для эмуляторов как правило и занимают 40 (32+8) или 24 (16+8) килобайт, хотя возможно есть и меньше)
Но очень быстро 8Кб на тайлы и 32Кб на код и данные перестало хватать и для расширения возможностей консоли в картриджи стали вшивать микросхемы переключения банков памяти - мапперы.
Чуть подробнее про них я напишу в следующий раз.
Очень интересно. Но что мне теперь делать с этими знаниями?
Necrys
> Очень интересно. Но что мне теперь делать с этими знаниями?
Порвать с зависимостью от ностальгии по старым 8-битным играм с денди. Когда знаешь как точно всё под капотом работает сразу пропадает магия очарования, а вместо этого в глаза начинают лезть огрехи графики, невозможность раскраски разными палитрами тайлов в шахматном порядке, смены фона только по горизонтали и тому подобное.
Лучшее исцеление от бесполезной траты времени на перепрохождение когда то шедевров прошлого в эмуляторах.
=A=L=X=
> Порвать с зависимостью от ностальгии по старым 8-битным играм с денди.
А я эмулятор писал,... правда, как раз на PPU и стопорнулся. Так и не смог найти у себя ошибку (то ли в PPU, то ли в декодере CPU), пару кадров оно работало как FCEU, а потом почему-то убегало куда-то не туда :( До мапперов у меня так и не дошло дело
0iStalker
> А я эмулятор писал
Все писали: http://www.gamedev.ru/flame/forum/?id=200961
0iStalker
> А я эмулятор писал,... правда, как раз на PPU и стопорнулся. Так и не смог
> найти у себя ошибку (то ли в PPU, то ли в декодере CPU), пару кадров оно
> работало как FCEU, а потом почему-то убегало куда-то не туда :( До мапперов у
> меня так и не дошло дело
Не удивлюсь. Там реально каша из кучи самых разных важных технических моментов. И большинство игр без мапперов и не должны работать и речь даже не про переключение банков памяти - я про это сейчас и хочу написать.
Мапперы NES/Dendy
Итак, мапперы. Разных мапперов было создано сотни разных видов и, возможно, до сих пор делаются новые.
Каких то стандартов особо нет - любой желающий может сделать чип, если его не устраивают присутствующие на рынке, расширив каким то образом функционал консоли.
Однако некоторые виды мапперов распространены чаще других. Создатели эмуляторов пронумеровали их по сути выделив первые номера самым часто используемым.
Из документации 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 адресных линии памяти видеоадаптера. Делалось это через картридж и без всяких мапперов в игру можно было "запаять намертво" один из этих режимов. Естественно в таких играх как "Черный плащ", где тип скроллинга менялся в некоторых местах на другой нужна была управляемая перекоммутация этих линий и за это в итоге тоже отвечали мапперы.
Характерно еще то, что игры первого поколения с удовольствием использовали горизонтальный скроллинг ровно в два экрана - игровое поле скроллилось, но довольно быстро упиралось в предел. Это неудивительно, потому что прямолинейно использовались 2 имеющихся видеостраницы. Скроллинг осуществлялся ровно в их рамках без "бесконечного проворачивания".
Вот, например, как выглядят обе видеостраницы в игре Bomberman, будучи горизонтально пристыкованы друг к другу:
а вот то же самое для игры Lode Runner:
Нетрудно заметить, что размеры поля в обоих играх полностью обусловлены двумя имеющимися видеостраницами в видеочипе. В том же бомбермене массив кирпичных стен в них же, очевидно, и хранился, что и объясняет одновременно и почему эта игра одна из редких, где было "много хранимых состояний" при отсутствии, однако, длительного скроллинга.
Итак, какие проблемы решали самые распространённые виды мапперов (далее я буду еще сильнее опускать некоторые незначащие для повествования детали, так что те кто в курсе не думайте что я пишу ошибки, просто опускаю неважное для краткости):
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 банк можно было заменить только целиком, такое приводило бы к перерасходу ПЗУ на одинаковые изображения главного героя, поэтому посадить банки тайлов на ОЗУ и обновлять их по строгой необходимости, когда один вид монстра покидает экран, а другой появляется, выглядит крайне разумной идеей.
К сожалению это удорожало картридж на цену 8Кб ОЗУ. Забавно, но в самой консоли не было столько ОЗУ - 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 просто невозможна по большому счёту без эмуляции маппера в картридже ибо сами картриджи в большинстве своём содержали заметно больше, чем просто переключатели банков памяти.
Да и сама возможность переключать банки памяти не закладывалась в консоль, как и многое другое.
P.S.
Хаха, оказывается MMC5 хотя и обладал тремя дополнительными звуковыми каналами, но в редакции консоли для североамериканского рынка (NES) эти каналы никуда не выводились на уровне железа, в отличие от оригинального японского Famicom или его клонов (того же денди).
Поэтому на картриджах той же Castlevania III для североамериканского рынка звук был упрощен до обычных каналов обычного денди. Поэтому тру-геймпер играет именно в японские картриджи (или их образы) именно на Famicom или её клонах.
Даже в эмуляторах можно прочувствовать разницу. Или вот видеосравнение:
В нём ровно на 1:00 происходит переключение с одной версии музыки на другую, так что можно сразу промотать до этого момента - 15 секунд и послушать.
=A=L=X=
Все эти мапперы в эмулях обязательно реализуются. Там слава богу их не сотни штук ;)
Dexus
> Все эти мапперы в эмулях обязательно реализуются. Там слава богу их не сотни
> штук ;)
Вот по этой ссылке: http://problemkaputt.de/everynes.htm#cartridgesandmappers есть списочек.
=A=L=X=
Мда, я читал что-то про около десяти разновидностей - может просто тут со всеми экзотиками. 85 маппер зачетный вообще.
=A=L=X=, весь тред не читал, есть информация о каких-нибудь особенностях реализации игр Snake Rattle 'n' Roll и Felix The Cat?