Помните статью про самую дешёвую консоль с Ozon — Sup GameBox? Тогда я рассказал вам о том, что у этого чуда инженерной мысли находится «под капотом» и почему эта консоль не так проста, как кажется на первый взгляд.

После статьи я решил написать письмо производителю процессора этой консоли. И что самое интересно — мне ответили! Даже Спустя 40 лет после релиза оригинальной NES, тайваньская компания V.R.T продолжает развивать архитектуру оригинальной NES. Мне больше ничего не оставалось, кроме как включить фен, достать программатор и хакнуть этот девайс...

❯ Предисловие

В прошлой статье мы с вами разобрали Sup GameBox и выяснили его главную тайну: на самом деле это не эмулятор, как думают многие, а полноценный аппаратный клон оригинального Famicom. Инженеры из тайваньской компании V.R.T не только реализовали полную совместимость с японской консолью, но и заметно доработали её архитектуру, превратив NES во что-то типа микроконтроллера с продвинутыми мультимедийными возможностями.

Та самая капелька!
Та самая капелька!

Мы также с вами выяснили то, что чипсет устройства способен работать не только с оригинальными картриджами, но и недорогими SPI/NOR-флэшками, а при наличии программатора мы теоретически сможем заменить существующие и даже добавить новые игры к и без того обширному ромсету из 500 самых известных релизов!

Однако в комментариях некоторые читатели задавали вполне логичные вопросы в духе мол «кто вообще будет производить новые чипы с аппаратными клонами NES, если какой-нибудь AllWinner F1C100s стоит буквально 2$ и при этом в разы мощнее оригинальной консоли? Наверняка это какие-то складские остатки, а компании уже давно не существует...». Всерьёз заинтересовавшись вопросом, я решил написать V.R.T письмо с восхищением, а также просьбой поделится информацией о чипсетах в Sup'ах:

London is capital of great Great Britain. Не судите мой рунглиш.
London is capital of great Great Britain. Не судите мой рунглиш.

И спустя неделю мне ответили! Я был в небольшом шоке и экстазе одновременно... Джек пояснил, что в GameBox'ах действительно используется чипсет VT38 или 39'ой серии, а также предложил использовать утилиту NesMaker с сайта компании для сборки собственного ромсета для консоли. Кроме того, Джек пояснил что реализация GameBox'а в виде девкита невозможна из-за пиратских игр, но вероятно компания прощупывает почву среди демосценеров и DIY'щиков — ведь сейчас, пожалуй, самые лучшие времена для любителей разрабатывать и собирать что-то своё!

Но пока девкита VT38 ещё нет, нам остаётся лишь ковырять и моддить уже существующие консоли... и это не так уж и сложно как кажется на первый взгляд! В первую очередь, важно понимать что Sup'ы собираются буквально «из того что было», при этом чипы памяти зачастую используются Б/У. Насколько мне известно, существует как минимум три ревизии консоли:

  • Первая использует NOR Flash в корпусе TSOP56 и имеет на борту 500 игр. Производитель флэш-памяти может быть любой, однако я чаще всего встречал чипы от Spansion. Объём флэши составляет 16МБ (но возможны отклонения в большую и меньшую сторону) и с этими чипами памяти связан определенный нюанс, о котором я расскажу чуточку позже.

  • Вторая тоже использует NOR Flash, однако уже в корпусе TSOP48, который можно прошить обычной копеечной колодкой для NAND-флэшек. Такой тип памяти встречается как минимум в версии 400 in 1 и его объём составляет 8МБ, однако судя по большому количеству стертых страниц и 0xFF в дампе — используется далеко не вся память!

  • Третья самая сложная — она использует специальные припаиваемые к плате адаптеры с BGA NOR-памятью. Эти адаптеры нужны неспроста: во первых многие дешевые фамиклоны используют однослойные платы, где развести пины под BGA может быть проблематичным, а во вторых BGA NOR-память ушла с рынка электроники лет так 15 назад, её в огромных количествах сдувают с устройств по типу спутниковых ресиверов и DVD-плееров и поэтому она стоит копейки на вторичке. Главная сложность заключается в сборке адаптера: @promolifeсмог такой собрать, но во время подготовки статьи мы с ним не общались.

Как вы уже могли понять, моя консоль относится к первой ревизии, что вносит определенные сложности. Дело в том, что для прошивки TSOP-56 флэшек необходимо покупать специальную колодку типа «A», которая стоит 1.500 рублей и более того — она подходит только для программатора XGecu T48! Один из моих зрителей компенсировал стоимость покупки программатора и колодки в полном объёме — за что ему огромнейшее спасибо!

Также спасибо читателю Alex за iPhone X — на него фото плат получаются просто изумительные!

Микросхема EPROM с BIOS'ом для 286-ноутбука старше меня почти на 10 лет...
Микросхема EPROM с BIOS'ом для 286-ноутбука старше меня почти на 10 лет...

И вот наконец-то весь комплект для прошивки приехал... пришло время снова разобрать консоль и включить фен!

❯ Делаем дамп

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

Обычно выводные микросхемы снимают паяльником с использованием сплава Розе или делают импровизированные SMD-щипцы для того, чтобы лишний раз не перегревать чип памяти. Однако я решил снять его феном в щадящем режиме, поскольку не хотел чистить пятачки от Розе после каждой переустановки микросхемы, да и при снятии TSOP феном риск сорвать п��тачки кратно ниже!

Далее мы отмываем плату и чип памяти от флюса, а затем вставляем его в колодку:

И выставляем параметры нашего чипа в программе Xgpro. Затем нажимаем «Verify» для проверки ID контроллера, дабы убедиться что все линии флэшки надежно прижаты к колодке и затем как минимум 3-4 раза вычитываем дамп с переустановкой чипа и последующей верификацией образов дабы точно убедится что всё прочиталось корректно.

И вот теперь начинается самое интересное: мы открываем дамп в HEX-редакторе и начинаем искать зацепки для того, чтобы примерно понять разметку памяти. Изначально я ожидал что в начале будет инициализация вектора прерываний, init-sequence для дисплея и код меню выбора игр, однако как оказалось — флэшка каким-то очень хитрым способом поделена на CHR ROM и PRG ROM, и при этом CHR ROM идёт первой!

«Наверняка названия игр хранятся в виде обычного ASCII-текста» — подумал я, так что мы сможем найти меню по ключевым словам — Mario, Angry Birds, Contra... Но никакого результата поиск текста не дал. Тогда я начал искать паттерны из CHR ROM того же самого Марио — и всё равно я не смог ничего найти. Единственное что напоминало об играх - нечитабельные ошметки названия игр.

Обратите внимание на Contra 1... Ну ведь почти то что нужно!
Обратите внимание на Contra 1... Ну ведь почти то что нужно!

Тогда я решил поизучать дампы Sup'ов других людей и наткнулся на пост darknesmonk с 4pda. Образ его консоли хоть и был практически идентичен моему, у него названия игр были корректными, а данные из PRG ROM и CHR ROM можно было найти по паттернам. И вот тут то я понял в чём заключается секрет!

Дело в том, что издавна существует очень простой аппаратный способ защиты кода от изучения и реверс-инжиниринга: перестановка битов на дата-линиях. Сама шина в процессоре остаётся точно такой-же, меняется лишь разводка на плате: там, где по логике должен быть бит (сигнальная линия) DQ8 — может оказаться бит DQ10, а там где DQ9 — DQ11 и наоборот. На последнем этапе подготовки прошивки запускается специальный скрипт, который переставляет биты так, чтобы они оказались на своём месте и по итогу для процессора всё остаётся прозрачным. Также поступили и разработчики Sup'а, перемешав биты DQ1 с DQ9 и DQ2 с DQ10.

Обратите внимание на странный порядок распиновки дата-линий.
Обратите внимание на странный порядок распиновки дата-линий.

На первый взгляд может показаться что инженеры пытаются что-то скрыть, однако на практике это скорее всего особенности трассировки платы: мы ведь не забыли, что она у нас однослойная? Иными словами, эти линии может быть проблематично подвести напрямую к процессору, а резисторы-нулевики ставить банально некуда, поэтому разработчикам пришлось выкручиваться вот таким костылем!

С виду трассировка у наших плат практически идентичная, особенно шина к флэшке, но почему у меня биты поменяны местами — мне так и непонятно.
С виду трассировка у наших плат практически идентичная, особенно шина к флэшке, но почему у меня биты поменяны местами мне так и непонятно.

❯ Реверсим

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

        private static bool GetBit(byte b, int bit)
        {
            return ((b >> bit) & 0x01) == 1;
        }

        private static void SetBit(ref byte b, int bit, bool value)
        {
            b = (byte)(value ? b | (1 << bit) : b & ~(1 << bit));
        }

        static void Main(string[] args)
        {
            const int firstBit = 1;
            const int secondBit = 2;

            if(args.Length < 1)
            {
                Console.WriteLine("Usage VTFasoler <ROM dump>");

                return;
            }

            string fileName = args[0];
            string ext = Path.GetExtension(fileName);

            FileStream input = File.OpenRead(args[0]);
            FileStream output = File.Create(Path.GetFileNameWithoutExtension(args[0]) + (ext == ".bin" ? ".fixed" : ".bin"));

            byte[] data = new byte[input.Length];
            input.Read(data, 0, data.Length);

            /* VT chipsets use whole 16 data lines, which means we have D1 swapped with D9 and D2 swapped with D10 */
            for(int i = 0; i < data.Length / 2; i++)
            {
                byte b1 = data[i * 2];
                byte b2 = data[i * 2 + 1];
                byte tmp = b1;

                SetBit(ref b1, firstBit, GetBit(b2, firstBit));
                SetBit(ref b1, secondBit, GetBit(b2, secondBit));

                SetBit(ref b2, firstBit, GetBit(tmp, firstBit));
                SetBit(ref b2, secondBit, GetBit(tmp, secondBit));

                data[i * 2] = b1;
                data[i * 2 + 1] = b2;
            }

            output.Write(data, 0, data.Length);

            output.Close();
            input.Close();
        }

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

Выйти на XRef'ы не получалось поскольку у меня нет опыта реверса программ для 6502 и я уже начал терять надежду... Однако я вспомнил что в основном, игры для NES имеют фиксированный формат с двумя секциями: PRG ROM (область памяти с кодом игры), а также CHR ROM (тут находится графика). Учитывая что в ромах .nes есть информация об используемом типе маппера и размерах секций PRG ROM/CHR ROM, мы можем подменять игры на нужные путем поиска секций существующих игр по паттернам и замены их на нужные! Однако такой способ подойдет только для игр с идентичными мапперами и размерами областей. Иными словами: мы можем заменить Dr. Mario с маппером типа 0 на хак Super Mario Bros или Battle City, но не сможем записать, например, Batman.

Сделать это просто: открываем нужную игру в HEX-редакторе, переходим на 5-й байт и смотрим размер PRG ROM, который указывается в блоках размерностью 16.384 байт. В следующем байте находится размер CHR ROM, который указывается в виде блоков по 8.192 байта. В Dr. Mario PRG имеет размерность 2 (32.768 байт), а CHR — 4 (тоже 32.768 байт).

Заголовок имеет размер в 16 байт.
Заголовок имеет размер в 16 байт.

Далее переходим на 17-й байт (при отсчете от единицы) и начиная от него выделяем столько же байт, сколько у вас получилось при умножении числа блоков PRG ROM на 16.384 - в моём случае 32768 байта и копируем их в буфер обмена.

Затем нам необходимо найти начало PRG ROM заменяемой игры: для этого выделяем 8 байт с отступом хотя-бы в 64-128 байт от начала секции (поскольку иниты в играх Nintendo очень похожи и можно случайно найти не ту игру) и записываем их значения в виде паттерна «78 D8 A9 10 8D 00 20 A2».

Если говорить простыми словами, то лучше выбирать паттерн начиная с адреса A0
Если говорить простыми словами, то лучше выбирать паттерн начиная с адреса A0

Далее ищем паттерн в нашем дампе и устанавливаем позицию курсора на начало секции PRG ROM, который в моём случае оказался по адресу 0x60000:

И просто вставляем скопированные ранее данные секции с заменой существующих данных. Получается вот так:

Тоже самое проделываем с CHR ROM, однако учтите что в начале этой секции у некоторых игр идёт стандартный шрифт. Поэтому паттерн лучше брать с смещения 64-128 байт от начала. Для проверки того, что вы нашли секцию от нужной игры, можно использовать замечательную программу YY-CHR, которая покажет её спрайты.

Осталось заменить название игры в пуле строк, не выходя за пределы нуль-терминатора, иначе мы сломаем названия других игр!

❯ Оно реально работает?

Пришло время записать наш дамп обратно на флэшку и посмотреть что у нас получилось в итоге!

Далее ставим флэшку на место, не забывая хорошо пропаять все её пины и отмываем флюс:

Момент истины: если консоль просто висит с черным экраном без подсветки — значит контакт одной из сигнальных линий был нарушен и необходимо пропаять чип ещё раз. У моей флэшки почему-то был немного гнутый корпус, поэтому иногда приходилось пропаивать по 2-3 раза перед тем как консоль включалась и стабильно работала. Далее выбираем наш хак Mario и...

Вот это графика, почти что SEGA Mega Drive! Не то что в оригинале!
Вот это графика, почти что SEGA Mega Drive! Не то что в оригинале!

Всё работает идеально!

❯ Заключение

Ну что друзья, как я и обещал — контенту с моддингом Sup'а быть! Конечно всё прошло не так гладко, как хотелось бы, но... кто знает, вдруг V.R.T действительно сделает какую-нибудь NES-совместимую DIY консоль, на которую игры можно будет легко заливать с помощью CH341A. А там глядишь и демосцена подтянется!

На данный момент, Sup GameBox — самый доступный гаджет для написания хоумбрю под NES и тестирования его на реальном железе... И кто знает, вдруг на нём когда-нибудь окажется игра моей собственной разработки...

А если вам интересна тематика ремонта, моддинга и программирования для гаджетов прошлых лет — подписывайтесь на мой Telegram-канал ‭«Клуб фанатов балдежа‭», куда я выкладываю бэкстейджи статей, ссылки на новые статьи и видео, а также иногда выкладываю полезные посты и щитпостю. А ролики (не всегда дублирующие статьи) можно найти на моём YouTube канале.

У меня также есть Boosty.

Очень важно! Разыскиваются девайсы для будущих статей!

А ещё я держу все свои мобилы в одной корзине при себе (в смысле, все проекты у одного облачного провайдера) — Timeweb. Потому нагло рекомендую то, чем пользуюсь сам — вэлкам.

Комментарии (11)


  1. bodyawm Автор
    01.11.2025 14:07

    В общем даже и не знаю что сказать по теме статьи) Планов у меня было больше: я хотел установить дополнительный 3.3В LDO для подсветки, припаять вторую флэшку поверх первой и вывести их CS на отдельный тумблер и залить большую библиотеку ромов NES...

    Но затем я понял, что игр под Mapper 0 не более нескольких десятков и многие из них уже есть в консоли, а ромсет под MMC3 теоретически и умещается в эти 16МБ. Других мапперов VT'шки пока не поддерживают...

    В сети уже есть доказательства возможности прошивки старых ревизий консоли, теперь есть факт прошивки и новой :)


    1. bodyawm Автор
      01.11.2025 14:07

      Ладно, не буду заниматься самообманом: статья вообще в подметки не годится тому, что я писал ранее. Проходняк короче :(


      1. Dimozy
        01.11.2025 14:07

        Откуда столько самокритики? Я еще дочитать не успел) Вы и так в рейтинге 2 место занимаете. Суббота люди отдыхают, выкладывать попробуйте в четверг) Без паники!!!


        1. bodyawm Автор
          01.11.2025 14:07

          Без самокритики нет развития)


          1. Dimozy
            01.11.2025 14:07

            С самокритикой, можно и до дурки доехать.) Критика: "Хорошо написано, запятых иногда мало, слишком длинные выражения мысли! Пойдёт такая критика? " Пробуйте чуть сокращать смысл, ну и классику конечно читайте. !!!


  1. promolife
    01.11.2025 14:07

    А мне понравилось читать, хорошая статья ))) чую дух авантюризма )) если есть желание - могу поделиться консолями для экспериментов.


    1. bodyawm Автор
      01.11.2025 14:07

      А есть ушатики?) Хочу поковырять с лог анализатором тестпоинты дисплея и попробовать на нерабочей консоли распаять RP2040


      1. tormozedison
        01.11.2025 14:07

        И получить карманный Мурмулятор с разъёмом для клавиатуры на боку?


        1. bodyawm Автор
          01.11.2025 14:07

          Не совсем, просто одну из вариаций своей консоли.


  1. VT100
    01.11.2025 14:07

    Ди-джей шли всех лесом!
    Крути, к чертям, шарманку!

    Разве что - добавить множественный выбор в опросы.


    1. bodyawm Автор
      01.11.2025 14:07

      Пока не думал об этом. А надо??