Как стать автором
Обновить

Nintendo DS: внутреннее устройство, принципы работы и взлом

Время на прочтение28 мин
Количество просмотров13K
Автор оригинала: Rodrigo Copetti
image

Оригинальная Nintendo DS (Blue edition). Выпущена 21.11.2004 в Америке, 02.12.2004 в Японии и 11.03.2004 в Европе.

Краткое введение


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

CPU


Как и предыдущая портативная консоль Nintendo, эта система основана на большом чипе под названием CPU NTR. «NTR» — это сокращение от «Nitro», кодового имени оригинальной Nintendo DS.

В CPU NTR реализована интересная многопроцессорная архитектура с использованием двух разных процессоров ARM, эта структура была создана ещё до того, как ARM Holdings официально начала выпускать многопроцессорные системы. Поэтому их работу с учётом существовавшего тогда уровня технологий можно считать довольно нестандартной.

Хоть это и не первая параллельная система, анализируемая в моей серии статей, её структура сильно отличается от остальных. Например, здесь нет «экспериментальной» конфигурации master-slave, с которой дебютировала Saturn, или «сопроцессорной» структуры, использовавшейся в PS1 или N64. Nintendo DS содержит в себе два независимых компьютера, способных выполнять самостоятельные операции, каждый из которых имел выделенную шину. Такая созависимость предопределила общую производительность консоли.

Давайте взглянем на эти два процессора:

ARM7TDMI



Структура и компоненты ARM7

Начнём с более знакомого нам, ARM7TDMI — это тот же самый процессор, который использовался в GameBoy Advance, но теперь работающий с частотой примерно 34 МГц (вдвое большей). Он по-прежнему содержит все свои возможности (в частности, Thumb).

Теперь расскажем об изменениях: так как инженеры Nintendo разместили ARM7 рядом с большинством портов ввода-вывода, этот процессор управляет операциями ввода-вывода и помогает им. Как видите, это не «главный» процессор, который отвечает за всю систему, а «подпроцессор», снимающий нагрузку с основного процессора, передавая данные множеству компонентов.

ARM946E-S



Структура и компоненты ARM9

Это «главный» процессор Nintendo DS, работающий с частотой примерно 67 МГц. Если забыть о печальной судьбе серии ARM8, то можно сказать, что ARM946E-S стала «некстген»-версией ARM7. Это ядро, являющееся частью линейки ARM9, не только унаследовало все функции ARM7TDMI, но и добавило нечто новое:

  • ARMv5TE ISA: по сравнению с предыдущей версией v4, она имеет несколько новых инструкций и более быстрый умножитель.
    • Буква ‘E’ в названии ядра означает Enhanced DSP, и это подразумевает, что многие из этих новых инструкций связаны с областями применения обработки сигналов.
  • 5-этапный конвейер: это прирост ещё одного показателя по сравнению с предыдущим конвейером из 3 этапов.
  • 12 КБ кэша L1: теперь ядро имеет кэш, в котором 8 КБ выделено под инструкции, а 4 КБ — под данные.
  • 48 КБ сильносвязанной памяти (Tightly-Coupled Memory), или TCM: она похожа на Scratchpad-память, однако в ней больший объём отдаётся инструкциям (32 КБ) в ущерб данным (16 КБ).

Nintendo также добавила к ядру следующие компоненты:

  • Блок делителя и вычисления квадратного корня для ускорения подобного типа операций (сам ARM9 неспособен выполнять такие вычисления).
  • Контроллер прямого доступа к памяти (Direct Memory Access, DMA): ускоряет передачу данных в память без зависимости от процессора. Благодаря использованию кэша процессор и DMA потенциально могут работать параллельно.

    • Кэш и DMA способны обеспечить большую производительность, но и создавать новые проблемы, например, проблему целостности данных. Поэтому программистам пришлось вручную поддерживать целостность памяти, например, очищая перед использованием DMA буфер записи.

Думаю, что учитывая наличие такого оборудования, легко понять, почему дети на самом деле любили эту консоль?

Взаимосвязь


Итак, мы рассказали о том, как два процессора работали по отдельности. Но чтобы работать как единое целое, им приходилось постоянно кооперироваться. Для этого оба процессора напрямую общались друг с другом при помощи специализированного блока FIFO; этот блок данных хранит две 64-байтных очереди (максимум 16 элементов) для двунаправленной коммуникации.


Схема блока FIFO

Это работало следующим образом: процессор-«отправитель» (тот, который должен был передать другому сообщение) помещал в очередь 32-битный блок данных, а процессор, имеющий роль «получателя» мог извлекать этот блок из очереди и выполнять с ним требуемые операции.

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

Основная память


Как и в предыдущем поколении консоли, ОЗУ распределена по множеству разных мест, что позволяло создавать приоритет размещения данных по скорости доступа. В целом, имелась следующая структура памяти общего назначения:


Модель ОЗУ консоли

  • 32 КБ WRAM (рабочей ОЗУ, Work RAM), работающей с 32-битной шиной: использовалась для хранения быстрых данных, общих для ARM7 и ARM9.
    • Помните, что одновременно к одному адресу имел доступ только один процессор.
  • 64 КБ WRAM c 32-битной шиной: тоже для быстрых данных, но доступ к ним имел только ARM7, как и в GBA.
  • 4 МБ PSRAM с 16-битной шиной: более медленный тип памяти, доступный процессору и управляемый блоком интерфейса памяти.
    • Pseudo SRAM (псевдо-SRAM), или PSRAM — это разновидность DRAM, которая выполняет обновление внутри чипа. Следовательно, она ведёт себя как SRAM (более быстрая, но и более дорогая альтернатива DRAM). Такая схема напоминает мне о 1T‑SRAM консоли Gamecube.

Обратная совместимость


Даже несмотря на серьёзное отличие архитектуры от архитектуры предшественницы, инженерам всё равно удалось сохранить критически важные элементы, обеспечивающие нативную совместимость с играми для GameBoy Advance.

Но для использования в DS «внутреннего» GBA в консоль был встроен набор программных процедур, переключающих консоль в режим AGB Compatibility Mode. При этом они фактически останавливают ARM9, отключают большинство «особого» оборудования, выполняют переадресацию шин, делают ARM7 главным процессором и снижают его частоту до 16,78 МГц. Далее ARM7 начинает загружать исходный AGB BIOS, запускающий картридж GamePak (точно так же, как сам GameBoy Advance). Тем не менее, этот режим всё равно демонстрирует некоторые особенности, отсутствующие в оригинальной консоли, например, отображение игры в чёрной рамке (в следующем разделе мы увидим, что в новой консоли разрешение экрана стало выше). Кроме того, поскольку DS имеет два экрана, пользователи могут выбирать, какой из них будет использоваться для отображения игры GBA.

После включения режима GBA пути назад нет, для повторного включения остального оборудования консоль необходимо перезагрузить.

Секреты и ограничения


Учитывая такое количество сложных компонентов, умещённых в один простой и недорогой чип, неудивительно, что возникали некоторые проблемы.

Неиспользованная мощь


Иногда я задаюсь вопросом, как Nintendo планировала способ использования двух процессоров, и учитывали ли разработчики, что выбранная ими структура повлияет на производительность.

Начнём с ARM9, этот процессор работает вдвое быстрее, чем ARM7, но большинство (если не все) операций ввода-вывода зависят от ARM7, поэтому ARM9 уязвим к простаиваниям в ожидании ответа ARM7. Мало того, внешняя шина ARM9 работает с половинной скоростью, поэтому возникает несколько «бутылочных горлышек».

К тому же шина основной памяти имеет ширину всего 16 бит. Следовательно, каждый раз, когда процессору нужно получить из памяти слово (шириной 32 бита), интерфейс приостанавливает процессор (ожидание может достигать до трёх циклов), пока не будет воссоздано полное слово. Сильнее всего это влияет на скорость, когда доступ к памяти не последовательный, из-за чего простаивание происходит при каждой операции доступа. Эта проблема также возникает при получении инструкций (к сожалению, в те времена ARM не поддерживал последовательное получение опкодов), что, к моему разочарованию, также влияет на код Thumb (потому что каждая операция получения 16 бит выполняется как 32-битный блок). С другой стороны, этот недостаток можно компенсировать благодаря полному использованию кэша и TCM.

В конечном итоге это означает, что в наихудшем случае «потрясающая» скорость ARM9 в 66 МГц практически снижается всего лишь примерно до 8 МГц. Так происходит, если программа ужасно использует кэш/TCM.

Вопрос о выборе оборудования


Когда я читал о процессоре GameBoy Advance, меня очень удивил потенциал ARM7: процессор не только выполнял предназначенные ему задачи, но и мог помогать с другими, например, с обеспечением секвенирования звука или созданием графики в псевдо-3D.

В процессе вывода ARM7 в коммерческую продажу ARM Holdings объединила усилия с DEC для создания высокомощной версии чипов ARM. Для этого DEC использовала структуру передачи данных своего процессора Alpha, и смешала её со структурой передачи данных ARM. В результате получилась новая серия процессоров, названная StrongARM, оказавшаяся на удивление быстрой. Ценой избавления от некоторых возможностей (Thumb и отладки) DEC смогла пересечь мегагерцовый порог и достичь скоростей до 233 МГц. Когда обычный пользователь собирался покупать новый PC на процессоре ARM (допустим, RiscPC), то он мог выбрать или машину со старым ARM710 на 40 МГц, или машину с StrongARM, работающим примерно на 582% быстрее. Влияние StrongARM было настолько фундаментальным, что ARM Holdings позаимствовала часть возможностей StrongARM для создания своей новой линейки процессоров, начиная с ARM9. Дальнейшее развитие истории нам известно.

Но вот в чём заключается мой вопрос: учитывая новые технологии в мире ARM, почему Nintendo в конечном итоге выбрала ужасно медленный ARM9 в сочетании с ещё более медленным ARM7, а не быстрый ARM9 (или даже StrongARM)? В то время другие компании как раз начали использовать StrongARM, например, Apple в своей линейке КПК Newton.

Я не хочу критиковать выбор Nintendo, но считаю, что этот вопрос нужно было обязательно задать, учитывая огромные объёмы зарождавшихся тогда технологий. Думаю, их выбор был вызван стремлением экономии заряда аккумулятора и снижения затрат на производство (благодаря использованию тех же процессоров, которые устанавливались в GBA).

Графика


Этот аспект немного необычен, ведь в консоли было не только два экрана для отрисовки, но и наряду с современным рендерером применялось сочетание традиционных тайловых движков.

Давайте начнём с физических характеристик: Nintendo DS содержит два ЖК-экрана, каждый из которых имеет размер 256x192 пикселя, то есть примерно на 20% больше пикселей, чем у GBA. Они могут отображать 262 144 цвета (18 бит) и обновляться с частотой примерно 60 Гц.

Архитектура


Графическая подсистема способна отрисовывать 2D и 3D-объекты. Первые состоят из двухмерной геометрии, заполняемой битовыми картами размером 8x8 пикселей (называемых тайлами), а последние отрисовывают трёхмерные объекты (четырёхугольники и прямоугольники) при помощи вершин.

Углубившись в изучение внутреннего чипа, управляющего этими экранами, мы заметим, что у консоли есть раздельное оборудование для 2D и 3D-геометрии. 2D-данные обрабатываются знакомым нам движком PPU (который теперь просто называется 2D engine), а 3D-данные обрабатываются совершенно новой подсистемой. Стоит заметить, что хоть это и не первая консоль, в которой появилась 3D-графика, она стала первой, в которой применяется собственная структура для рендеринга 3D-графики.


Схема разных графических блоков

Эти движки должны быть привязаны к одному из экранов, и для 2D-игр это не проблема, потому что для каждого экрана есть свой 2D-движок. Однако для тех игр, которые хотят продемонстрировать современные технологии, есть только один 3D-движок. Следовательно, 3D-функции одновременно доступны только на одном из экранов. А как насчёт объединения 2D и 3D-объектов? Это возможно; позвольте мне объяснить каждый из движков по отдельности, чтобы мы могли обсудить это позже.

Построение кадра с 2D-графикой


Перед изучением каждого этапа рекомендую прочитать в предыдущей статье о PPU консоли GBA, потому что здесь я упомяну только те изменения, которые позволяют создавать 2D-игры «следующего поколения». Кроме того, поскольку существует два движка, один называется Main, а второй — Sub. Это не обязательно означает, к какому экрану подключен каждый из них. С другой стороны, Main содержит немного больше функций, чем Sub.

Чтобы объяснить на примере, на этот раз я позаимствую графику из New Super Mario Bros.

Тайлы



Некоторые из тайлов, находящихся во VRAM. Для демонстрации используется стандартная палитра

Теперь мы знаем, как в целом работает система тайлов, но как конкретно управляются тайлы на этой консоли? Доступно 656 КБ VRAM, и эта область разделена на разные банки: четыре по 128 КБ, один по 64 КБ, один по 32 КБ и три по 16 КБ. Программисты могут заполнять банки графикой и указывать движку, где находятся требуемые данные. Оба движка могут считывать любые из этих банков, но не могут получать доступ к нескольким одновременно.

Тем не менее, существуют определённые ограничения на распределение данных. Например, ARM7 может получать доступ только к двум банкам по 128 КБ. В то же время, эти два банка не могут хранить спрайты, а доступ к последнему банку на 16 КБ имеет только движок Sub. Есть и другие ограничения, но принцип понятен.

Ещё один аспект — 3D-движок, который мы рассмотрим ниже, получает доступ к некоторым из этих банков для чтения текстур.

Типы фонов


Со времён Super Nintendo блок PPU обеспечивал всё большую гибкость при построении слоёв фонов. 14 лет спустя мы получили чип, способный читать тайлы и применять множество аффинных преобразований; более того, слой в конечном итоге может создаваться из буфера кадра.

Прежде чем мы приступим к обсуждению различных режимов, в котором может работать 2D-движок для генерации фонов, позвольте показать этот список с типами фонов, генерируемых движком:

  • Группа символьных типов: эти типы фонов соответствуют традиционной системе тайлов, кадр рендерится заполнением его тайлами.
    • Фон Static или Text: обычный фон. До 512x512 пикселя, 256 цветов и 16 палитр. Он содержит все стандартные эффекты (отзеркаливание по горизонтали/вертикали, скроллинг по горизонтали/вертикали, мозаика, альфа-смешение), плюс дополнительный эффект «затемнения». Может использоваться до 1024 тайлов.
    • Фон Affine: фон с аффинными преобразованиями. Однако он не позволяет отзеркаливать по горизонтали/вертикали и способен получать только 256 тайлов (четверть от максимального числа). Этот слой имеет размер 1024x1024.
    • Фон Affine Extended: такой же, как affine, но поддерживает полное количество тайлов и отзеркаливание по горизонтали/вертикали.
  • Группа битовых типов: вместо обработки тайлов движок воспринимает VRAM как буфер кадра. Все режимы наследуют эффекты, доступные из символьного аффинного фона.
    • 256 colours Extended: использует буфер кадра размером 512x512 пикселя.
    • Direct colour Extended: похож на предыдущий, но в нём буфер кадра поддерживает до 32 768 цветов (15 бит).
    • Large screen: съедает всю область 128 КБ VRAM для рендеринга большого буфера размером 1024x512 пикселя.

Эти режимы нельзя выбирать произвольно, консоль предоставляет набор режимов фонов с различными сочетаниями.

Режимы фонов



Layer 0


Layer 2


Layer 3
Используемые аффинные слои. Layer 0 преобразуется в реальном времени для имитации движения облаков

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

  • Mode 0: 4 статических слоя.
  • Mode 1: 3 статических слоя + 1 аффинный слой.
  • Mode 2: 2 статических слоя + 2 аффинных слоя.
  • Mode 3: 3 статических слоя + 1 расширенный аффинный слой.
  • Mode 4: 2 статических слоя + 1 аффинный слой + 1 расширенный аффинный слой.
  • Mode 5: 2 статических слоя + 2 расширенных аффинных слоя.
    • Это самый часто используемый режим, потому что он невероятно гибок.
  • Mode 6: 1 статический слой, отрисовываемый 3D-движком + 1 large screen.
    • Так как место есть только для одного буфера кадра, этот режим доступен только для Main.

Спрайты



Отрендеренный слой спрайтов

Спрайты, или «объекты» наследуют все функциональные возможности из PPU консоли GBA, но имеют два важных дополнения.

Во-первых, OAM (область, в которой хранятся записи спрайтов) теперь имеет размер 2 КБ, что позволяет отображать на экране до 128 спрайтов на кадр. Следовательно, каждому из движков выделяется по 1 КБ.

Во-вторых, OAM теперь может ссылаться на битовые карты из VRAM, а не только использовать тайлы и палитры. Это ещё одно отличие от системы тайлинга. На самом деле, оба спрайтовых «режима» могут сосуществовать в одном кадре, потому что эта опция задаётся для каждого отдельного спрайта.

Результат



Все слои объединены… чего-то не хватает?

Так как каждый слой рендерится на лету, на последнем этапе всё объединяется и отправляется на выбранный экран. Это почти то же самое, что происходит в предыдущих консолях с PPU, но значит ли это, что работа закончена?

Ещё нет! Main всё ещё должен получить слой из ещё одного движка, самого мощного из них.

3D-ускоритель


Если вы играли в Nintendo DS, то знаете, что эта консоль способна отображать определённое количество 3D-графики. В отличие от графики некоторых игр для GBA, она не обрабатывается процессором. CPU-NTR содержит два компонента, составляющих 3D-движок. Довольно любопытно, что использованная Nintendo структура напоминает мне о RCP компании SGI.

Если вы вернётесь к разделу «Режимы фонов», то заметите, что каждый режим имеет по крайней мере один статический фон, потому что этот слой можно заполнить графикой, созданной 3D-движком. Единственная тонкость заключается в том, что это может делать только Main, и это одна из причин, по которой Mode 6 доступен только движку Main.

Движок геометрии



Архитектура движка геометрии

Если вы читали какие-нибудь из статей о консолях четвёртого или пятого поколений, то можете задаться вопросом: а где же SIMD-процессор? Это правильный вопрос, потому что ARM9 не особо хорошо справляется с векторными операциями и я не думаю, что для этого достаточно отдельного делителя. Именно поэтому Nintendo встроила в консоль компонент под названием Geometry Engine, занимающийся преобразованием вершин, проецированием, освещением, усечением, отсечением и сортировкой полигонов. Последняя функция необходима для правильного использования функций прозрачности.

Этот движок имеет строгие ограничения, в частности, на количество полигонов, которое он может обработать: доступны дополнительные 248 КБ ОЗУ, используемые для хранения обработанной геометрии; эта величина позволяет хранить до 2048 треугольников или 1706 четырёхугольников, хотя этот предел снижается из-за использования полос полигонов (а не отдельных полигонов). Чтобы получить представление о значении этого числа, рекомендую изучить разделы «interactive models» из предыдущих статей: вы увидите, что это ограничение довольно серьёзное, но не забывайте, что и разрешение у этой консоли гораздо меньше, что немного компенсирует проблему.

Как бы то ни было, этот движок управляется при помощи Command FIFO, заполняемого данными из процессора или DMA. FIFO хранит 256 элементов, однако дополнен ещё одним буфером под названием PIPE, который хранит ещё четыре команды (что в сумме даёт 260).

Движок рендеринга



Архитектура движка рендеринга

Это растеризатор, отвечающий за генерацию пикселей и наложение текстур. Для последней операции он использует коррекцию перспективы и затенение по Гуро. Более того, устройство обеспечивает такие современные функции, как Z-буферизацию, альфа-смешение, стенсил-тесты, туман и сглаживание.

Однако система рендеринга довольно непривычна: вместо рендеринга в буфер кадра она исопльзует рендеринг в буфер строк, который заполняется растровыми строками, как и в 2D-движке. Так происходит потому, что движок должен синхронизироваться отрисовщиком 2D. Для каждого четырёхугольника рендерер может заполнять только по одному интервалу на растровую строку, и это может быть довольно неудобно, потому что результат может оказаться искажённым, например, если четырёхугольник вогнутый или имеет пересекающиеся рёбра.

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

Результат



О, вот это уже неплохо

Вместо записи результатов обратно в буфер кадра для отображения движок рендеринга выполняет запись в блок под названием Colour Buffer, хранящий до 48 растровых строк. Каждая растровая строка получается 2D-движком для заполнения слоя BG0 в порядке FIFO.

3D-рендеринг начинается до 2D-рендеринга, что позволяет последнему при необходимости применять преобразования к новому слою. Main также позволяет захватывать 2D, 3D или сгенерированный комбинированный кадр, смешивать его с ещё одним кадром во VRAM и записывать результат обратно во VRAM, которую затем можно отобразить.

С точки зрения контроля, движок рендеринга также позволяет изменять свои параметры посередине кадра благодаря использованию механизма на основе двойной буферизации; он хранит копию старого состояния, пока завершается отрисовка текущего кадра. Поэтому никакого смещения изображения (tearing-а) не происходит.

Сравнение известных игр


Одни из первых игр, выпущенных для этой консоли, пытались походить на игры с другой консоли (а именно Nintendo 64). Поэтому я бы хотел вкратце объяснить, почему игроки могли видеть значительные различия между двумя версиями:

Первый пример



Super Mario 64 (1996 год), отрендерен с разрешением 320×240 пикселей


Super Mario 64 DS (2004 год), отрендерен в разрешении 256x192 пикселя

Второй пример



Mario Kart 64 (1996 год), отрендерен в разрешении 320×240 пикселей


Mario Kart DS (2005 год), отрендерен в разрешении 256x192 пикселя

Давайте объясним происходящее в кадре на основании того, что говорят люди на форумах:

  • Текстуры NDS выглядят более угловатыми → движок рендеринга не применяет никаких фильтров, поэтому текстуры интерполируются по принципу «ближайший сосед».
  • Текстуры NDS выглядят насыщеннее → движок рендеринга не ограничен 4 килобайтами TMEM, ему доступно до 512 КБ VRAM (наряду с механизмами сжатия), поэтому можно загрузить больше данных.
  • Модели на NDS имеют пикселизированные края → модели на NDS рендерятся с более низким разрешением, чем на N64.
  • Вдалеке текстуры NDS выглядят искажёнными → движок рендеринга не использует координаты с плавающей запятой и субпиксельной точности. Свой вклад в искажения вносят и низкое разрешение с отсутствием mip-mapping.

Таковы различия вкратце, более специализированные особенности можно узнать при глубоком изучении обоих движков и дизассемблинге обеих игр, чтобы разобраться, какие в них есть функции и как они используются.

Модели


Я дополнил wee model viewer алгоритмом «ближайший сосед», что позволяет визуализировать модели Nintendo DS на GPU. В оригинале статьи модели можно покрутить мышью.

New Super Mario Bros (2004 год), 636 треугольников



Модель


С текстурами

Nintendogs (2005 год), 750 треугольников



Модель


С текстурами

Несмотря на то, что мы говорили о множестве ограничений графической подсистемы, многие игры использовали её по-настоящему эффективно.

Звук


Большинство улучшений звука касалось в совершенствовании каналов PCM, которые имелись у GBA. Как мы видели ранее, игры GBA отдавали приоритет программному секвенированию в ущерб PSG, и результат был довольно впечатляющим.


Last Window: The Secret of Cape West (2010 год). Демонстрация вывода микшированного стерео

Поэтому в новой аудиосистеме присутствует 16 каналов PCM, что позволяет передать задачи микширования оборудованию. PCM-сэмплы могут быть 8-битными (в стиле GBA), 16-битными (оптимальное разрешение) или ACPCM (сжатый вид). Как бы то ни было, микшер создаёт 32-килогерцовый стереосигнал, который можно воспроизводить через динамики (теперь стерео) или наушники. Также микшер может записывать полученные стереоданные во WRAM, что позволяет субпроцессору (ARM7) накладывать эффекты (например, реверберацию).

Мы ничего не забыли? Забыли — поскольку консоль может запускать игры GBA, у неё должно быть нечто, напоминающее PSG (реализованное программно или аппаратно). Выясняется, что последние 6 каналов могут стать PSG (любой из них синтезирует или импульс, или волну произвольной формы, а два из них создают импульс или шум).

С учётом всего сказанного, означает ли это, что Nintendo DS наконец-то может воспроизводить закодированную музыку (например, MP3)? Это возможно (на самом деле, множество самодельных программ реализовали такое воспроизведение в той или иной форме), но декодирование звука занимает большую часть полосы пропускания и вычислительных ресурсов. Поэтому секвенирование звука остаётся наиболее реалистичным вариантом.

Интерактивное сравнение


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

Мне пришлось немного увеличить усиление GBA-саундтрека, чтобы нормализовать громкость, что влияет на соотношение сигнал-шум (помните об этом, переключаясь между дорожками). Надеюсь, это даст вам представление о том, как эволюционировала звуковая подсистема.

Некоторые проблемы


Сейчас я расскажу о некоторых сложных случаях: SNES имела уникальные функции звука, которые не так просто было воссоздать на этой консоли, их тоже можно послушать в интерактивном виджете в оригинале статьи.

В первом примере слышно (особенно на последних 10 секундах), что сложно конкурировать с возможностями, которые предоставлял компонент S-SMP консоли SNES.

Ввод-вывод


Если вкратце, то ввод-вывод целиком обрабатывается ARM7. На самом деле, с этим CPU практически ничего не происходит, кроме передачи данных, что сильно расстраивает.

Доступ к картриджам и памяти


В консоли есть интерфейс внешней памяти, соединяющий три конечные точки: Slot-1 (куда подключаются картриджи Nintendo DS), Slot-2 (куда подключаются картриджи и аксессуары GBA) и 4 МБ PSRAM (основная память). К этому интерфейсу могут получать доступ оба CPU, но он содержит регистры, которые можно изменять для повышения приоритета одного CPU над другим на случай выполнения двух одновременных запросов по одной шине.


Модель внешней памяти с указанием ширины шины данных

Важный аспект: карты DS не привязаны к памяти, поэтому для считывания данных игры любым процессором содержимое необходимо сначала скопировать ОЗУ. Это выполняется отправкой блокам картриджей 8-битных команд, ссылающихся на 32-битные адреса. После них данные можно получить вручную, доставая их из 32-битного регистра или через DMA. Шина данных имеет ширину 8 бит, но может достигать скоростей до 5,96 МБ/с (по утверждениям Nintendo).

К используемому для сохранений «backup»-чипу (например EEPROM, FLASH или FRAM) доступ осуществляется через шину SPI (последовательную), которая использует собственный набор команд и подключена к 24-битной адресной шине.

Картридж Slot-2 привязан к памяти исходным расположением контактов, однако в режиме DS адреса смещены для адаптации к оборудованию, предоставляющему расширенную функциональность (дополнительное ОЗУ, вибрация и т.д.). Как и у GBA, шина ROM имеет ширину 16 бит, а шина RAM — ширину 8 бит.

Периферия


ARM7 также подключен к ещё одному узлу SPI, связанному интерфейсом с контроллером сенсорного экрана, который управляет нижними экранами (имеет резистивный тип, поэтому для работы необходим стилус), и к флэш-памяти (где хранится прошивка, подробнее об этом ниже).

Любопытная особенность этого сенсорного экрана заключается в том, что кроме распознавания позиций X/Y, он также может возвращать диагональную позицию (используемую для вычисления «значения давления», представляющее собой область, к которой прикладывается давление). К сожалению, об этом никогда не говорилось в официальном SDK, поэтому, насколько я знаю, ни в одной игре не использовалась эта незадокументированная особенность (кроме самодельных homebrew-игр).

Многие говорили, что в «Hotel Dusk: Room 215» эта функция использовалась в одной из головоломок, где игрок должен был одновременно коснуться экрана двумя пальцами. Однако это не так: после экспериментов с отладчиком no$gba выяснилось, что в головоломке не используются данные о давлении. Вместо него она проверяет, изменились ли сильно значения x/y. Игра интерпретирует этот эффект так, как будто игрок нажал на экран двумя пальцами.

Головоломка


Hotel Dusk: Room 215 (2007 год) с вышеупомянутой головоломкой с распределительным щитом. Чтобы спасти девушку, игрок должен одновременно свайпнуть по экрану двумя пальцами, чтобы включить свет

Неудача


Но если сделать это неправильно...

Наконец, в том же стеке находятся часы реального времени, или RTC.

Беспроводная сеть


Также консоль содержит контроллер беспроводной сети, работающий в полосе частот 2,4 ГГц и обеспечивающий инновационные возможности:

  • Игра по Интернету: позволяет любой игре подключаться к LAN-сети по стандартному соединению Wi-Fi.
  • Многокартная игра: до 16 консолей обмениваются друг с другом данными по проприетарному протоколу.
  • Однокартная игра: игра может загрузить программу на другую DS, в которую не вставлена карта с игрой.

Операционная система


Думаю, можно с уверенностью сказать, что к этому поколению каждая консоль выпускалась с каким-нибудь интерактивным интерфейсом. NDS наследует модель предыдущей операционной системы, состоящей из легковесных API для упрощения доступа к вводу-выводу, но также предоставляющей минимальный интерфейс пользователя для изменения параметров и некоторых «приложений».

Вместе с тем, её операционная система разделена на несколько чипов, поэтому давайте начнём с тех, которые считываются при загрузке.

Точка входа


На определённом этапе ARM7 и ARM9 потребуется инициализировать оборудование и для этого NTR-CPU содержит два отдельных небольших чипа ROM:

  • BIOS 4 КБ, подключённый к шине ARM 9.
  • BIOS 16 KB, подключённый к шине ARM 7.

При запуске консоли каждый CPU загружается с соответствующего ROM. Так происходит, потому что их вектор сброса указывает на каждый чип (для справки: вектор ARM9 находится в 0xFFFF0000, а вектор ARM7 — в 0x00000000).

Каждый BIOS хранит два набора процедур: код загрузки и вызовы прерываний. Последнее неудивительно, учитывая историю предыдущей консоли, однако первое повысило сложность: кроме инициализации оборудования, код ARM 7 также занимается защитой, выполняя проверки в картридже DS (если он вставлен).

После выполнения кода загрузки оба CPU синхронизируются, чтобы они могли начать действовать как «единая машина»: оказывается, что ARM 9 завершает загрузку намного раньше ARM 7, поэтому ARM 9 отправляет ARM 7 4-битное значение, простаивает в полубесконечном цикле, ожидая ответа ARM 7, а после ответа оба пересекают финишную линию одновременно, так сказать, находясь теперь в синхронизации.

Окно возможностей


Если у вас есть или была DS, то вы, вероятно, замечали, что играть в игры можно только если картридж вставлен до включения консоли. Так происходит потому, что BIOS процессора ARM 7 при загрузке выполняет проверки картриджа (подробнее об этом в последнем разделе) и если все тесты завершаются успешно, исполняемый файл игры ARM 7 копируется во WRAM, а исполняемый файл ARM 9 копируется в основную память.

Если по какой-то причине исполняемые файлы не скопированы (из-за того, что картридж ненастоящий или не найден во время загрузки), то игру невозможно запустить и пользователю придётся перезагрузить консоль.

Интерактивная оболочка


Вне зависимости от наличия игры, система завершает загрузку, загружая интерактивную оболочку. Это просто программа, остающаяся во внешней Flash-памяти на 256 КБ.


Главный экран


Заставка. Вы видите этот экран при каждом включении DS. Логотип Nintendo отображается, если вставлен правильный картридж


Экран Settings. Тот же чип хранит прошивку, а также некоторые пользовательские параметры (язык, имя, дата рождения, будильник и приветственное сообщение) с системными параметрами (калибровка сенсорного экрана, флаг первого запуска, версия прошивки и параметры Wifi).

Оболочка более-менее сравнима с оболочками других консолей того же времени. Пользователи используют её для запуска игры, изменения параметров, скачивания игры (с помощью Download Play) или работы с Pictochat: открытой чат-комнаты, где можно пообщаться с соседними Nintendo DS.

Стоит подчеркнуть, что данные только для чтения и записываемые данные находятся в одном перезаписываемом чипе, поэтому теоретически можно перезаписать прошивку! К счастью (и по очевидным причинам), Nintendo защитила верхнюю часть чипа (64 КБ) от записи, поместив на нужное место материнской платы перемычку SL1, которую можно увидеть, сняв отсек для батарей. Тем не менее, перезапись остальной части флэш-памяти тоже приводит к катастрофическим результатам!

Обновляемость


Несколько раз (если точно, то пять) Nintendo обновляла прошивку, чтобы пропатчить уязвимости защиты. Обновления не устанавливались пользователями (вспомним о защите перемычкой SL1). Nintendo встраивала обновлённую прошивку в следующие изготавливаемые партии консоли.

Игры


О, здесь можно сказать многое, особенно из-за того, что возможности консоли вдохновили многих программистов и художников на придумывание действительно инновационного дизайна.

Носитель


Эта консоль может запускать игры с трёх источников, но только два из них могут использовать все возможности оборудования:


Пример игры

  • NDS или картридж Slot-1: это основной носитель, используемый для загрузки нативных игр DS. Это единственный носитель, который использовался для распространения игр.
  • GBA или картридж Slot-2: этот разъём позволяет консоли запускать игры GameBoy Advance; поскольку игры Slot-1 тоже могут получать доступ к этому источнику для расширения возможностей игр NDS сюда можно было вставлять картриджи расширения. Они обеспечивали такие функции, как увеличение ОЗУ, новые способы ввода и устройства обратной связи (например, устройство вибрации rumble pack).
  • Download Play или Wireless MultiBoot: этот эволюционировавшая версия оригинального Multi-Boot, позволяющая другой консоли с игрой NDS скачивать программу с помощью беспроводной связи. Загружаемый контент хранится в WRAM и запускается после завершения передачи. Так как WRAM энергозависима, после перезагрузки данные теряются.
    • Авторизированные розничные магазины использовали эту функцию для создания Download Stations, в которых пользователи при посещении магазина могли скачивать демо игр.

Структура программы


Мы уже видели, что BIOS необходимо было разделить с отдельным кодом для ARM9 и ARM7; примерно то же самое происходило и с играми. Поэтому карты NDS состояли из следующих областей:

  • Заголовок (4 КБ): содержит метаданные (расположение каждого исполняемого файла, серийные номера и т.п.).
  • Область защиты (16 КБ): используется в целях защиты от копирования. В последнем разделе статьи мы расскажем о ней подробнее.
  • Основной контент (переменного размера): остальная часть карты просто содержит исполняемые файлы и данные игры (графику, звуки и т.д.). Розничные игры, в которых использовался SDK Nintendo, содержат упорядоченные иерархически данные с файлами и папками благодаря встроенной файловой системе.

Экосистема разработки


Для игровых студий, желавших разрабатывать игры для консоли, Nintendo распространяла и аппаратные комплекты, и SDK со множеством утилит.

Оборудование


Комплект разработки (devkit) под названием IS-NITRO-EMULATOR состоял из средних размеров синей коробки, содержащей основную часть внутреннего оборудования и устройств ввода-вывода DS. За ним идёт толстый кабель, подключённый к фальшивому корпусу Nintendo DS, используемому в качестве «контроллера» и дисплея. По запросу комплект разработки дополнялся такими возможностями, как вывод звука/видео, Wifi (по умолчанию его эмулировали с помощью Ethernet) и отладчик. Я думал, что последняя функция включена в комплект по умолчанию, но вспомнил, что эти устройства могут использоваться и в отделах тестирования.

Комплект считывает карты DS, но другого типа, с корпусом побольше и заменяемыми чипами backup. Эти карты прошиваются с помощью другого устройства под названием IS-NITRO-WRITER.

Программное обеспечение


Программный комплект содержит утилиты для взаимодействия с комплектом разработки, тулчейны C/C++ и API оборудования. Стоит упомянуть, что в документации указан явный запрет на любой обход API для прямого доступа к оборудованию: даже несмотря на то, что игры будут запускаться на «голом железе», Nintendo не допускала их распространения, если они выполняют «запрещённые» операции. В их число входит прямое управление ARM7, превышение разрешения дисплея или отключение ЖК-экранов.

Для введения таких норм есть понятные причины, например, сохранение уровня качества. Однако, честно говоря, я считаю, что запрет на использование ARM7 для чего-то другого, кроме задач ввода-вывода — пустая растрата потенциала…

Свобода взаимодействия



Dr Kawashima's Brain Training (2005 год). Новые категории игр привлекали к консоли новую аудиторию.

Благодаря новым видам взаимодействия студии получили возможность отдавать приоритет не графике, а геймплею.

Впервые в истории потребительской электроники у устройства появился сенсорный экран, микрофон, Wifi и часы реального времени. Тем не менее, некоторые игры даже добавляли новые виды взаимодействий, например, рекомендовали пользователю повернуть консоль вбок.

Сетевой сервис


После успеха предыдущего конкурента Nintendo присоединилась к клубу онлайн-мультиплеера и реализовала свою централизованную инфраструктуру. Игры, использующие Internet Play, могли подключаться к серверам Nintendo (называвшимся Nintendo Wi-Fi Connection).

Антипиратская защита и Homebrew


Хотя на карты DS не подействовало проклятие компакт-диска, Nintendo реализовала системы защиты, чтобы сохранить контроль за распространением игр.

Система шифрования


Nintendo DS в основном использует симметричную систему шифрования для шифрования связи между интерфейсом памяти и картой Slot-1. Прежде чем мы обсудим способ реализации шифрования, давайте поговорим об используемых алгоритмах и генерации ключей (которые используются для выполнения шифрования).

Область заголовка карты содержит значение под названием Gamecode (уникальный идентификатор игры), интерфейс памяти берёт этот блок для генерации KEY1 и использует его для шифрования дальнейших команд, передаваемых карте. Шифрование KEY1 основано на алгоритме Blowfish.

Далее KEY1 смешивается со значением внутренних часов и некоторыми другими значениями заголовка картриджа для генерации нового ключа под названием KEY2. Его фундаментальное отличие от KEY1 заключается в том, что первый использует случайные значения, чтобы сделать его непредсказуемым. В шифровании KEY2 используются множественные операции XOR и Shift для обфусцирования данных.

Проверка карты DS


Как мы видели ранее, BIOS содержит процедуры, проверяющие карту NDS при запуске. Работает это следующим образом:

  1. Консоль получает идентификатор чипа (chip ID) картриджа, сохраняет его в ОЗУ, а затем включает шифрование KEY1.
  2. Первые 2 КБ области «Secure area» тоже копируются в ОЗУ. В первых 8 байтах этого фрагмента хранится строка под названием Secure Area ID, а следующие значения содержат контрольные суммы (тип CRC16) и другие метаданные.
  3. «Secure Area ID» уже зашифрована с помощью KEY1, однако снова шифруется при помощи KEY2, а затем расшифровывается. Если расшифрованное значение соответствует строке encryObj, то проверка карты прошла первый тест. После этого строка уничтожается, чтобы помешать обнаружению алгоритма. Если проверка прошла неудачно, то 2 КБ области Secure Area заполняются мусором, что не позволяет считать остальную часть карты.
  4. Второй тест состоит из повторного получения chip ID и его шифрования с помощью KEY2 случайное количество раз (seed зависит от внутреннего таймера). Если значение chip ID соответствует первому сохранённому chip ID, то пройдена вторая проверка.
  5. Затем остальная часть Secure area запрашивается в случайном порядке и воссоздаётся в ОЗУ. После этого происходит исполнение прошивки.

Если всё прошло хорошо, то прошивка найдёт требуемый исполняемый файл карты в ОЗУ, что позволит пользователю запустить игру. В противном случае селектор игры будет показан серым.

Защита Download Play


Программы, получаемые через Download Play, должны быть подписаны Nintendo при помощи RSA-подписи (приватный ключ знает только Nintendo).

Эта проверка выполняется прошивкой.

Поражение


Если вы были пользователем homebrew во времена популярности консоли, то, вероятно, имели множество возможных вариантов для запуска этого ПО. Однако до обнаружения всех существующих взломов хакерам с трудом удавалось обходить сложную антипиратскую систему Nintendo.

Имеющийся Slot-2


Так как GBA-подсистема всё равно исполняет картриджи без защиты (если не считать трюки с торговыми марками), уже созданные флэш-карты GBA были совместимыми с NDS. Это позволило запускать самодельные игры для GBA, которые нормально работали, если игрокам были не важны все новые функции, существовавшие только в играх DS.

Как всегда, флэш-картриджи также позволяли запускать спираченные ROM, однако поскольку Nintendo не могла изменить систему защиты GBA (потому что в таком случае некоторые игры потенциально перестали бы работать), компании пришлось просто с этим смириться.

Расширенный Slot-2


После более глубоких исследований BIOS и прошивки консоли DS хакеры наконец обнаружили, что исполнение карты NDS можно перенаправить на разъём GBA. Карта NDS ещё не была взломана, однако этот способ позволил условно обходить систему защиты карт Slot-1 исполнять программы Slot-2 в режиме DS.

Таким образом, на рынке появилось новое поколение флэш-карт Slot-2. Они содержали в себе код ARM9, который исполнялся при запуске с Slot-1. Сам запуск выполнялся при помощи одного из этих обнаруженных способов (называемых «passthrough methods»):

  • Использование карты PassMe: для этого требуется настоящая карта Slot-1. PassMe — это своего рода адаптер, вставляемый между Slot-1 и настоящей игрой. По сути, он изменяет заголовок, отправляемый с карты консоли, чтобы обманом убедить консоль исполнить код Slot-2, загружая в процессе картридж Slot-2.
  • Использование WifiMe: требует компьютера с совместимой картой Wi-Fi. При помощи модифицированного драйвера можно транслировать специализированную программу, которую можно скачать на DS с помощью Download Play. После загрузки она будет перенаправлять исполнение на Slot-2. Этот способ эксплуатировал тот факт, что прошивка не проверяет RSA-подписи некоторых областей двоичного файла.
  • Использование FlashMe: устойчивое решение. Добавив его в цепочку к предыдущему способу и подключив терминал SL1, можно было запустить homebrew-программу, способную перезаписать прошивку так, чтобы при наличии флэш-картриджа загрузка выполнялась с Slot-2. Этот хак также устранял проверку цифровой подписи, чтобы можно было загружать homebrew и из Download Play.

Как и ожидалось, Nintendo выпускала версии DS с обновлённой прошивкой, патчившей эти трюки. Поэтому хакеры пытались найти другие способы, с основном на основе эксплойтов BIOS (которую пропатчить сложно).

Нативный Slot-1


Разработчик знаменитого эмулятора Nintendo DS под названием NO$GBA Мартин Корт позже смог извлечь BIOS и выполнить реверс-инжиниринг защиты Slot-1. Благодаря этому новые инструменты и документация раскрыли истинные механизмы защиты Nintendo DS. Как вы видели из моей статьи, система шифрования работала до тех пор, пока не выполнили её обратную разработку (это ограничение систем симметричного шифрования, в отличие от систем ассиметричного шифрования, например, RSA, в которых приватный ключ никогда не хранится).

Как бы то ни было, это привело к появлению огромного количества флэш-карт Slot-1 формата plug-and-play, работавших на любом типе консоли и выполнявших программы Nintendo DS нативно. Способ passthrough method также был усовершенствован с дебютом карт NoPass, позволявших загружать флэш-карты Slot-2 без необходимости настоящей игры.

Так как систему шифрования нельзя было модифицировать без внесения изменений, влияющих на все продававшиеся игры, Nintendo проиграла эту битву. Единственное, что ей оставалось — пойти по юридическому пути, как это было и с предыдущей консолью.

Это моё личное мнение, но меня поражает, насколько флэш-карты проще других homebrew-способов на предыдущих консолях. В старых статьях я рассказывал, что если пользователи хотели запускать homebrew-программы или пиратские игры, то им приходилось забираться глубокого в дебри и использовать какой-нибудь сложный способ.

В случае DS флэш-карты в буквальном смысле продавались как розничные игры, и мне кажется, что игровым студиям было очень мучительно наблюдать за популярностью пиратства.

Ещё меня удивляет количество появившихся на рынке брендированных флэш-карт (не говоря уже об их фальшивых копиях). Если посмотреть с технической точки зрения, то флэш-карты — это просто SD-адаптеры. Единственное, что отличает одну карту от другой — это загрузочный код и устройство чтения SD. Некоторые изготовители вкладывали больше усилий для создания улучшенного диспетчера файлов (называвшегося kernel/firmware) и использовали дополнительное оборудование.

Вот и всё, ребята



Моя нынешняя DS, которую я использовал для этого исследования. Первую свою консоль я продал уже очень давно… Интересно, где она сейчас.

Итак, кажется, я рассказал 99% того, что хотел…

Надеюсь, критика некоторых аспектов выглядела не слишком жестокой. Поймите меня правильно — я всё равно считаю эту консоль качественным инженерным устройством! Но в ней присутствуют определённые дефекты, из-за которых я задавался вопросом: это компромисс между ценой и возможностями или один из архитектурных недочётов. Честно говоря, это не мешало одиннадцатилетнему мне мечтать в своё время об этой консоли. Поэтому для компании Nintendo это значит, что её «миссия выполнена»!

Источники/дополнительное чтение


Общая информация



CPU



Графика



Операционная система



Игры



Защита от пиратства



Фотографии


Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Всего голосов 23: ↑23 и ↓0+23
Комментарии2

Публикации