Уже к моменту написания предыдущей статьи, ко мне шли очередные подопытные экземпляры тетрисов и первым был получен вот такой:
Подобные тетрисы ориентировочно стали появляться в продаже в конце нулевых. На нем я опробовал новый способ декапсуляции кристалла, боясь повторения предыдущей неудачи. Суть следующая: капля компаунда нагревается феном до такой степени, чтобы он стал мягким, но при этом не хрупким (градусов 150). Не прекращая нагрев, аккуратно подцепляем скальпелем компаунд и пытаемся его отклеить - сначала от платы, а затем, с особой осторожностью, и от кристалла. Звучит довольно просто, но на деле не очень. И хотя у меня было три удачных попытки из трех, вероятность повредить кристалл неосторожным движением пинцета все еще высока, но зато нет необходимости в использовании какой-либо химии, что в домашних условиях очень удобно.
Итак, кристалл первого тетриса:
Ожидаемо, техпроцесс гораздо плотнее. К сожалению, никаких опознавательных знаков, только число 2008, скорее всего это год создания маски.
Не буду пытаться глубоко анализировать, но если кратко: в правом верхнем углу 7.5КБ ПЗУ (которое прочитать визуально через оптический микроскоп думаю будет крайне сложно), под ней 384Б ОЗУ. В левом верхнем углу, по всей видимости, дешифратор инструкций (по нему можно попробовать идентифицировать микроконтроллер). Боюсь ошибиться, но предположу, что это 8-битный микроконтроллер, который к HT-443 не имеет никакого отношения.
Следующий тетрис попал ко мне в виде кучки внутренностей, поэтому я не знаю, как он выглядел в свои лучшие годы. На плате указана дата 12/8/2002 и судя по расположению кнопок - это типичный 1 in 9999 начала нулевых. Вот фотография его кристалла:
Абсолютно та же архитектура и почти та же площадь кристалла, только компоновка несколько отличается. 3КБ ПЗУ, 160Б ОЗУ. Опять никакой идентификации, только год(?) - 2003.
А вот и главный виновник торжества, со скромным названием Super Brick Game E-23 PLUS MARK II 99 IN 1 от тайваньской компании E-Star:
Капля компаунда у него была гораздо больше чем у предыдущих двух, поэтому с декапсуляцией я провозился пол часа, но результат того стоил:
Старый добрый HT-943 (он же HT443A0), только на год старше экземпляра из предыдущей статьи.
Для сравнения размеров кристаллов сделал групповое фото:
По четырем экземплярам, конечно, выводы делать рано, но можно предположить, что основной платформой Brick Game в начале и середине 90-х, когда они еще производились в Тайване были 4-битные микроконтроллеры Holtek, а к концу 90-х - началу 00-х, когда подобные игрушки стали массово выпускаться в Китае, основная платформа поменялась на какую-то, которая была ближе к местным фабрикам.
Чтение ПЗУ
Естественно, меня в первую очередь интересовало ПЗУ, но первый взгляд на него разочаровал - практически нечитаемо:
К счастью, оказалось, что если освещать кристалл под углом, то результат становится гораздо лучше, хоть и не идеальным:
Теперь отчетливо видны границы переходов от "нормальных" транзисторов к тем, у которых увеличена толщина слоя оксида под поликремнием, что делается для увеличения порогового напряжения транзистора, при котором он никогда не открывается (можно считать, что его там нет). На следующем изображении красными точками отмечены "нормальные" транзисторы, слой подзатворного окисла которых позволяет им открываться сигналом выборки с дешифратора:
Как же теперь превратить эту кашу битов в последовательность байт или другими словами получить образ ПЗУ с которым уже можно будет работать дальше?
В прошлой статье я немного затронул эту тему, но постараюсь здесь рассказать подробнее, тем более, что задача оказалась труднее, чем я ожидал.
Рассмотрим ПЗУ и ближайшие окрестности подробнее:
Как я уже отмечал, биты одного разряда каждого байта кучкуются группами, которые на изображении выше отмечены черными прямоугольниками. Чтобы правильно прочитать байт, необходимо определить старшинство разрядов. Для этого можно проследить внутреннюю шину (с которой соединена каждая из групп) до дешифратора инструкций, в котором старшинство восстанавливается через описание инструкций в даташите. Определенный таким образом номер разряда на изображении подписан цифрой.
Сверху можно выделить 12 повторяющихся групп транзисторов (отмечены цветными прямоугольниками) от каждой из которых на лини дешифратора вокруг ПЗУ уходит пара сигналов - прямой и инвертированный (отмечены цветными линиями соответственно группе). Естественно предположить, что этими линиями задается 12-битный адрес считываемого байта, а группы транзисторов формируют схемы регистров счетчика инструкций, стека (он здесь одноуровневый) и некоторой вспомогательной логики. Для правильного порядка чтения байт опять же необходимо определить, как линии дешифратора соотносятся с последовательностью разрядов адреса. Здесь немного сложнее, чем в случае с разрядностью битов. Все 12 разрядов соединены с 8-битной внутренней шиной, старшинство разрядов которой мы уже выяснили. Получается часть разрядов (левые и правые четыре группы) делят младшие разряды шины между собой. Поэтому дополнительно пришлось проанализировать управляющие линии регистров - они полностью совпадают для правых восьми групп и отличаются для четырех левых. Значит четыре левых бита адреса заносятся в счетчик инструкций отдельно от 8 правых из чего я сделал предположение, что они старшие. Номера разрядов адреса также подписаны на изображении.
Есть два момента, которые мне не удалось выяснить без детального восстановления схемы: какая из пары линий дешифратора несет прямой сигнал, а какая инвертированный и то же самое с битами. Получается есть 2 варианта порядка чтения из ПЗУ и 2 варианта чтения байта - вполне приемлемо.
Но на практике я столкнулся с некоторыми проблемами. Для начала я вручную прочитал по десятку байт каждого из вариантов, дизассемблировал его и не увидел там того, чего ожидал. А ожидал я, исходя из информации в даташите, что встретит меня что-то типа безусловного перехода на нулевом адресе, с которого стартует микроконтроллер после сброса. Те же безусловные переходы я ожидал увидеть по 4 и 8 адресу куда прилетают прерывания, ну или в крайнем случае reti если они не используются. Но нет, один вариант был страннее другого и мне пришлось перепроверять кучу других, менее вероятных порядков чтения ПЗУ, которые не вписывались в описанную выше теорию. Ничего не добившись в итоге, я выбрал один из первых четырех вариантов, который был более-менее нормальный и продолжил читать ПЗУ постепенно убеждаясь, что это действительно верный вариант чтения, просто авторы прошивки полностью проигнорировали прерывания и вообще использовали несколько неожиданные инструкции вроде декремента ячейки памяти сразу на старте и вывода 0xE на порт PA который никуда физически не подключен:
000: dec [R3R2] ;0F
001: timer on ;38
002: mov A, 0xE ;7E
003: out PA, A ;30
004: mov R1R0, 0xFF ;5F0F
006: in A, PP ;34
007: ja0 04C ;804C
009: mov A, 0xF ;7F
00A: call E67 ;FE67
00C: jmp 002 ;E002
Эмулятор
Итак, убедившись, что на верном пути, я продолжил расшифровывать ПЗУ, параллельно отлаживая на нем эмулятор, который я начал писать немного раньше. После нескольких дней такой работы, прошивка была восстановлена полностью, эмулятор в целом отлажен, явные ошибки в образе ПЗУ исправлены. Наконец, я увидел заветные "01" на дисплее, испытывая примерно такие же чувства, как Виктор Франкенштейн кричащий "Оно живое!".
Конечно, сначала было не так красиво - из сегментов дисплея я к тому времени добавил только часть игрового поля. Кстати, восстанавливая карту сегментов, поразился, на сколько же они располагаются не однотипно: у одной цифры сегменты адресуются одним образом, у соседней другим, часть игрового поля так, другая сяк - не завидую программистам которые писали код для этого дисплея.
Эмулятор пока сыроват (например, совсем нет звука) и не факт, что я доведу его до ума, но уже сейчас может вполне помочь в исследовании прошивки, если кому-то будет интересно написать свой эмулятор или поискать возможные пасхалки. Можно и просто поиграть, поностальгировать :) Приложение поддерживает базовые средства отладки, содержимое всех регистров и ОЗУ можно менять на лету. Написано на Python с использованием PyQt6, так что может запускаться на всех поддерживаемых этой библиотекой ОС (Linux, Windows и macOS). Исходники доступны на github, там же можно найти образ прошивки.
Скорее всего, еще остались ошибки, поэтому, если у вас есть такая же модель тетриса и вы заметите разницу в поведении с оригиналом, напишите, попробую исправить.
Комментарии (87)
dlinyj
13.11.2023 08:30+18Очень ждал вашей статьи, честно. Очень хабратортно и невероятно круто.
По эмулятору можно прям отдельную статью написать, как же вы его разрабатывали. А то вопросов осталось больше, чем ответов на них :).
Транслятора этого кода не нашлось, чтобы поиграться самому и может какое-то описание архитектуры у вас появилось?Azya Автор
13.11.2023 08:30+13Спасибо! Вот даташит, а вот дизассемблированный код.
dlinyj
13.11.2023 08:30+4Возможно я немного не внимательно читал даташит, но я не понял как там адресуется дисплей.
Кстати, восстанавливая карту сегментов, поразился, на сколько же они располагаются не однотипно: у одной цифры сегменты адресуются одним образом, у соседней другим, часть игрового поля так, другая сяк - не завидую программистам которые писали код для этого дисплея.
Каким образом удалось сопоставить какой сегмент дисплея приходит на процессор, просто прозвонкой? Особенно интересно всякие дополнительные символы справа.
Azya Автор
13.11.2023 08:30+41При снятых поляризационных фильтрах и определенном угле освещения дорожки на стекле неплохо просматриваются:
Конечно не все сегменты получилось так локализовать, что-то выяснял методом тыка.
dlinyj
13.11.2023 08:30+6Вы меня просто восхищаете проделанной работой! Теперь можно написать свою игру для тетриса!
И никогда не попробовать её реализовать в железе...
DMGarikk
13.11.2023 08:30+5меня всегда интересовала индикация фруктов справа дисплея, по какой логике они работали...в моем тетрисе который был у меня я видел максимум 2 значка но их существенно больше... интересно были ли варианты где они както активно использовались?
dlinyj
13.11.2023 08:30+1Есть исходный код, эмулятор. Осталось написать транслятор и можно будет понять :)
lx13s
13.11.2023 08:30+3Насколько я помню, фрукты заполнялись снизу вверх на основе набранного количества очков в одной конкретной игре. Затем они начинали исчезать, также снизу вверх. В самом тетрисе, естественно, тяжело набрать такое количество очков, но бывали игры, в которые можно было играть практически вечно.
Azya Автор
13.11.2023 08:30+2Немного поискал по коду - не нашел вообще обращений к нибблам памяти, которые отвечают за эти сегменты, по всей видимости, в этом тетрисе фрукты полностью игнорировались.
vladkorotnev
13.11.2023 08:30+2Интересно, что у правых двух цифр нет перекладины — там всегда нули? Напомнило, как на поздних электромеханических пинболах вместо одного из разрядов счётчика был просто прибитый гвоздями сектор от оного с нулём %)
Труд монументальный, конечно. Ещё с тех пор как мы пересеклись на МК90 следил за вашим творчеством и тихо охреневал, а тут впечатления уже вообще цензура не пропустит :-)
NemoVors
13.11.2023 08:30+5Можно тупой вопрос? Вот эта капля - для чего она служит? Для защиты чипа от повреждений или это попытка запретить вам сделать то, что вы в статье делали?
DanilinS
13.11.2023 08:30+17Защита от повреждения и внешней среды. Использование такого монтажа сильно удешевляет производство.
Yak52
13.11.2023 08:30+10Это просто один из видов самого дешманского корпуса для кристалла.
zatim
13.11.2023 08:30+6Точнее, это т.н. бескорпусной монтаж. Для такого монтажа выпускаются также транзисторы и другие п/п детали. Вот, например, микросборка передатчика советской милицейской рации. Мелкие точки, залитые каплей компаунда с тремя отходящими проволочками - бескорпусные транзисторы.
Azya Автор
13.11.2023 08:30+5В первую очередь, конечно, механическая защита. В какой-то степени она также способствует ограничению в изучении и копировании, но тем, кто действительно хотел, получить доступ к кристаллу труда никогда не составляло.
grishkaa
13.11.2023 08:30+7Неистовая крутота.
Прошивки, кстати, вполне могут быть универсальными между несколькими моделями тетрисов. Когда я был маленьким, глупым, и мне было нечем заняться, я игрался со своими электронными игрушками, но не совсем по назначению. Точно помню, что у меня пару раз случайно получалось сделать так, чтобы тетрис показал не свою обычную заставку, а другую, от другой модели. Сейчас я взрослее и умнее, и понимаю, что то, что я тогда сделал, называется глитчинг по питанию и является вполне валидной техникой для, например, обхода всякой защиты. Даже модчип для Nintendo Switch работает по такому принципу.
Вполне может быть, что модель задаётся какими-нибудь перемычками на самой плате или подключением кристалла к ней. Правда, в дизассемблированной прошивке я вижу чтение только из тех портов, к которым подключены кнопки (PP и PS).
Azya Автор
13.11.2023 08:30+2Я сравнивал прошивку из этой статьи с теми кусками ПЗУ, которые фотографировал в предыдущей и они не совпадают. Думаю, что универсальные прошивки появились позже, может как-раз не тех контроллерах, о которых я написал в начале.
Alohahwi
13.11.2023 08:30+1Я тоже глитчингом по питанию занимался в детстве, замыкая батарейку отверткой, и тогда ещё(в 1990х) понял что процессор в этих тетрисах 4х битный, потому что сложность и скорость были от 0 до 15. Причем я прошел все скорости от 0 до 14. На 14 скорости фигуру можно было сдвинуть на одну клетку в сторону за один сдвиг вниз, на 15 - на ноль клеток, т.е. управление просто отключалось при достижении 15й скорости. Часы электроника, модели 51-55, были на 6 битных процессорах, там часы/минуты/секунды были от 0 до 63. Потом в 2000х купил тетрис, там процессор 8 битный уже стал.
MaFrance351
13.11.2023 08:30+2Я таким же образом умудрился найти пару скрытых игр на каком-то картридже от Sega...
gxcreator
13.11.2023 08:30+4Кстати, восстанавливая карту сегментов, поразился, на сколько же они располагаются не однотипно: у одной цифры сегменты адресуются одним образом, у соседней другим, часть игрового поля так, другая сяк - не завидую программистам которые писали код для этого дисплея.
Думаю разработчики для этого дела приспособили макросы, тут проблема больше для реверс-инжениринга.
Azya Автор
13.11.2023 08:30+1Так макросы проблему спрячут, а вот мигать из-за медленной перерисовки тетрисы не перестанут.
NickDoom
13.11.2023 08:30+2Блин, четырёхбитники меня прямо очаровывают своим минимализмом. Хочется что-нибудь даже поизобретать такое, с 16 командами, без регистров (всё на стеке, но с произвольным доступом на 16 ячеек вглубь), с общей памятью (сначала масочное ПЗУ с библиотеками сложения-умножения, потом NAND, потом DRAM), заточенное изначально архитектурой команд под построчную работу с DRAM, в общем, чтобы плотность кода и данных была как в нейтронной звезде :) Эдакий даже не микро-, а наноконтроллер :-D Можно SRAM для простоты, но DRAM соблазняет дополнительным паззлом по рефрешам :)
ciuafm
13.11.2023 08:30+10К сожалению вы не в тренде. Недавно мне отдали на разборку не работающую электро сигарету. Так там китайцы умудрились впихнуть 32 битный ARM (bat32g137) плюс ещё две специализированных микросхемы - зарядник usb-c и драйвер светодиодов на 16 выходов/256 уровней (aw9523b). У меня блин первый комп имел процессор попроще, а тут ...
SergeyNovak
13.11.2023 08:30+2Зачем там вообще микроконтроллер?
isden
13.11.2023 08:30У меня где-то валяется электросигарета, так там даже rtc запихали (соотв, в ней есть часы). Еще видел в магазине аппарат с fm приемником. Извращались кто как умеет, я не удивлюсь если кто-то андроид туда вкорячивал.
vorphalack
13.11.2023 08:30андроид вряд ли, но моды с сенсорным экраном и наворотами вплоть до пароля на включение - имеют место быть.
N1X
13.11.2023 08:30Потому что заказчик пришел с "нужно вчера прототип и термоклея и отладочной платы из под стола", а потом "О, норм, в продакшн!". Если девайс мелкосерийный - сейчас никто не морочится... Потом если продается - соптимизируют, нет - ну нет, так нет...
iiiytn1k
13.11.2023 08:30Ковырял одну электросижку (бокс-мод), так там вообще стоял внешний 16-битный АЦП.
ciuafm
13.11.2023 08:30Не, в моей АЦП встроенный, всего 12 бит, зато на 1 Msps. Плакал когда увидел ...
vorphalack
13.11.2023 08:30боксмод и вообще "большие" вейпы это совсем другая тема, там например бывают никелевые койлы, которые имеют NTC, и это надо учитывать, обсчитывать и крутить выдаваемый ток соответственно. а вот то, что такой уровень дошел в условные "одноразки" - несколько удивляет, это какая ж там себестоимость у этих чипов с платами стала? еще пару лет назад все "мозги" были в прямом смысле таблеткой а-ля электретный микрофон.
ElectricPigeon
13.11.2023 08:30+2Теперь отчетливо видны границы переходов от "нормальных" транзисторов …
Подскажите, пожалуйста, как вы это определили? Я смотрю на фотографию, и не могу понять, чем отмеченные на следующем фото транзисторы отличаются от неотмеченных.
Azya Автор
13.11.2023 08:30+1Надо смотреть не на пересечения, которые отмечены и все одинаковые, а на промежутки между ними по вертикали.
Gadabio
13.11.2023 08:30+2Впечатляющая работа! В детстве мне родители было купили один из первых, видимо, Brick Game. Потому что в нем было всего 8 или 9 игр. И вот среди них были классные гонки. В которых нужно было не просто уворачиваться вправо-влево от препятствий. А еще и можно было собирать разные бонусы. Которые в процессе игры давали возможность машинке стрелять и пробивать себе дорогу сквозь препятствия. А может и не только это, не помню уже.
К сожалению, тот тетрис я было вывел из строя. Как и еще потом один в процессе сборки, разборки и всяческих опытов...
В более поздних моделях Brick Game, в которых была возможность поиграть таких гонок мне уже не попадалось.
LoadRunner
13.11.2023 08:30+1Помню два типа гонок - просто трасса, где надо обгонять другие машины, стараясь не врезаться в них, и с препятствиями, где можно было стрелять.
Очень тяжело было во втором разобраться без туториалов.
dlinyj
13.11.2023 08:30+1Я одну глупую вещь спрошу, пытался тщетно запустить ваш эмулятор на разных платформах (Centos, Mint(читай Ubuntu), но потерпел фиаско. На убунте ставил:
sudo apt install python3-pyqt6.sip pip3 install pyqt6
Но получаю всё равно:
python3 main.py
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.Available platform plugins are: xcb, minimalegl, vkkhrdisplay, linuxfb, wayland-egl, offscreen, wayland, eglfs, minimal, vnc.
Аварийный останов (образ памяти сброшен на диск)
Даже психанул и поставил qtcreator (будь он не ладен):
sudo apt install qtcreator
Те же проблемы. Библиотека xcb на которую ругается, у меня стоит:
sudo apt install libxcb-xinerama0 .... Уже установлен пакет libxcb-xinerama0 самой новой версии (1.14-3ubuntu3).
Что я делаю не так?
LTS-Pettrov
13.11.2023 08:30+2Статья супер! Чисто теоретически можно под эту платформу написать сокобан, обозначая игрока и точки разной частотой мигания
Sau
13.11.2023 08:30+1Для экрана 20 на 10: можно сапёра ещё, шашки (и игры на их основе, уголки, например), нарды, блэкджек, морской бой.
LTS-Pettrov
13.11.2023 08:30+1на счет шашек и.т.п наврятли, но сокобан вполне хватает 10х20
dlinyj
13.11.2023 08:30Только градаций серого нет.
LTS-Pettrov
13.11.2023 08:30ну я предположил что можно это реализовать частотой мигания как в некоторых играх ТЕТРИСА
Azya Автор
13.11.2023 08:30+2По даташиту обновление дисплея 64 кадра в секунду и они с таймером завязаны на одну базовую частоту, так что в теории можно мигать сегментами получая еще комфортные 32 кадра и серый цвет без мерцания. Но конечно, проверить это можно только на физическом устройстве, то есть нельзя)
Kotorkovsciy
13.11.2023 08:30+1Интересно увидеть реверс брик гейма у которого есть возможность подключения второго брик гейма для совместной игры, но как мне кажется, основная трудность это найти подобный экземпляр
impwx
Очень крутое исследование. Хабр снова торт :)
Azya Автор
Спасибо!