Sonic - from SMS to TS Config
У меня никогда не было приставок.
После выпуска РасМаn я начал искать – что ещё есть из аркад, которые были бы очень популярны, и подходили под мои требования для переноса – z80, интересная игра, хотя-бы минимальное техническое описание для разбора кода. Заодно поиск шёл не только по аркадным кабинетам.
Метался я много – смотрел в сторону РС8000, оценивал код игр под 8080, да много чего перебрал.
Оказалось, что «всё не так просто» ;) По аркадам – дичайший зоопарк по оборудованию.
Да, часто линейка игр использует свой стандартный набор оборудования. Но при этом часто это однотипные игры.
В аркадах часто используются по несколько процессоров, и довольно часто — разных типов. Например – 68000 и z80, либо же z80 и z80, один 6502 и т.д. и т.п. Точно так-же – народ не лимитирует себя и в звуке. Использовать несколько АУ, комбинировать АУ и ФМ чипы – это нормально. Использовать второй процессор сугубо для генерации звука – это тоже нормально :) Некоторые аркады используют больше двух процессоров.
Довольно интересно и не привычно – многопроцессорные 8бит системы? Неожиданно!
В результате – я нашёл нечто, что вполне могло сделать мне ненадолго некоторое настроение – galaxian. Клёвая игра, типа. Основана на железе пек-мена, но со своими особенностями: типа область памяти, указывающая на сдвиг строк в экране.
Да, она заработала, начала что-то показывать, но их способ разработки меня раздражал. Писало игру явно несколько человек, и каждый использовал свои подходы к реализации.
В общем, не смотря на то что игра уже отрабатывала основные циклы, строила на экране картинку и прочее – я её забросил.
Потому что – древняк. Потому что – скучно сейчас в это играть. Потому что – не то.
Надо что-то интересное.
Продолжающийся поиск привёл меня к приставкам на z80. Их не так много, и последняя из приставок, использующая z80 как main cpu – оказалась Sega Master System. Не самая продаваемая, но со своей коллекцией хитов.
Я просматриваю их каталоги игр на предмет скачать – вижу пачки платформеров, и вдруг вижу Соника. Хо!
Загрузка бинаря в spg, грузим в эмуль, начинаю проходить – гм, очень даже толковый код, всё продумано. Работаем с адреса 0, используем im 1, юзается rst #28 и подобные непривычные обычному спектрумисту команды :)
При старте очищается область #c000-#dfff, что-то пишется в порты #BF, но далее – начинается инициализация начального цикла, и вызовы, команды, вызовы, команды, команды, переходы …
Но, при этом – код очень хорош. Выглядит отлично – продуманно.
Однако! Отличный вызов.
Чёрт, похоже – это будет интересное путешествие…
Ищу доки. Что за порты? Почему такая память (#c000-#dfff) для переменных?
Оказывается, SMS имеет всего 8к памяти.
Оказывается, SMS имеет пагинг памяти для страниц 0,1,2.
Оказывается, SMS имеет свой видеочип, основанный на популярной тогда микросхеме TMS9918A, но изменённой, и называемой VDP.
И да, картридж с 256к.
Что предлагает их видеочип?
— 16 кб видеопамяти, адресуемой портами
— Сдвиговые регистры (X,Y) для отображения экрана
— тайловый слой, тайлы размером 8х8. Можно флипить X и Y, можно их показывать поверх спрайтов. Набор – до 512 возможных, но увы – меньше. Память 16к общая на всё :)
— 64 спрайта, заданным размером: 8х8 или 8х16.
— 32 цвета из набора 64х, по 2 бита на цвет. 16 цветов – на тайлы, 16 – на спрайты.
— разрешение 256х192
— 16ц на всё
Гм, блин же. Система очень даже легко ложится на возможности конфы, и при этом остаётся ещё очень много доступных ресурсов!
Чо там со звуком? Непонятно. Чип с прямоуголкой, 4 канала, один на шум. Да и ладно, сейчас совсем другие заботы.
Гуглю, много гуглю. SMSPower! отлично собрал доки, реально отлично.
Опыт подсказывает – гугли ещё и с добавлением строки «source». Отличное попадание! Есть отличный разбор исходника с большим проставлением меток и комментариями – гит от Kroc Camen. WOW! SUPERB! Чёрт, всё становится гораздо понятней!
Клонирую репу. Исходник собирается только под асемблер WlaDX. Зверь странный, но интересный. Исходник – собирается. Собранное – работает под эмулем Emulicious.
Пишу благодарственное письмо Kroc, что-то пытаюсь поправить.
Управление памятью – через маппинг. Меняю ld (_RAM_FFFE_), a на call set_page2 и подобные вещи – отлично всё укладывается по байтам.
Начинается очень плотное погружение в игру, да и в их систему вообще.
Но удивительно – асм Ville начинает ругаться – память переписана!
Изучаю его асм, обнаруживаю удивительную фичу – его асм умеет сравнивать подложенный исходник с компилированной версией, и после этого – отмечать изменённые места (команда .background)! Такой фичи я не видел нигде.
Отписываюсь ему, и через пол часа получаю письмо! Этот великолепный финн, работающий в ROVIO, продолжает работу над своим асмом, и постоянно его дорабатывает!
Я показываю ему, что использую версию 2004го года, на что он отвечает что слишком старая версия, собери мол новьё. А оно всё под unix-а, виндового бинаря нет, я в прострации.
И вдруг — Ville идёт к родителям, у которых есть вин 7, ставит там студию, компилит и отправляет мне.
Ville я тебя обожаю! :) Спасибо!
Использовав возможность его асма – отметить места с исправлениями как замещаемые области (.unbackground), я уже знаю – моя область памяти изменяется, остальные чётко фиксированы побайтно. Это надёжно.
Ну и, по большому счёту – лучше поглядите на спецификацию по ассемблеру. Хорош, на самом деле, пусть и не привычен синтаксисом.
На мобилке – пачка док по sms. Чтение доков по системе на ночь и в свободное время. Разбираюсь что она может; какие биты, отправляемые в порты VDP за что отвечают.
Система начинает проясняться.
Задача оказывается отличной. Это будет просто мощно. Работы – много, но вещь – очень достойна.
И ЭТО МОЖНО СДЕЛАТЬ, это переносимо на мою систему.
…
Копаюсь в текущих, насущных деталях. По дороге выясняется, что их 16ц – это вообще не наш 16ц. У них – слои.
Каждый байт из набора 4х байтов – это набор битов для 8ми точек. Бит 7 первого байта, бит 7 второго, бит 7 третьего и 7ой бит четвёртого – это 4 бита (16 цветов) для первой точки. Бит 6 этих четырёх байт – и вторая точка готова.
Класс, блин. Норм чип, конечно. Ну ок, это решаемо. Сконвертим. Пишу.
Итак, их память – 8кб. После #e000 всё свободно. Отлично. Займу всё что нужно :)
Первая попытка по конверсии графики и вывода видна на видео с пати. Я за неделю – разместил всё в памяти, сделал управление нею, сконвертил битпланы, добрался до вывода тайлов, проямолинейно подвигал их биты цвета в нашу палитру, сделал процедуры вывода тайлового слоя на экран, и оно даже что-то начало показывать.
Для пати это было уже что-то, а приготовить хоть ЧТО-ТО для ВАУ на пати — очень хотелось :) Парни-то в курсе что такое Соник!
Все разъехались, я в размышлениях. Предыдущая процедура вывода на экран абсолютно не годилась для работы. Да, это была демонстрация, но это не будет использовано. Я выводил тайлы которые должны были быть на экране — в тайловую память.
Всё не так. Это не работает. Надо размышлять.
Читая как работает система, я прихожу к выводу, что необходимо создать эмуляцию работы VDP.
Система показывает блок из своей тайловой памяти, причём координаты вывода из него заданы по X и Y. Надо повторять их подход.
Организовываю область видеопамяти, в которую пишет игра. Она будет отдельна. Организовываю процедуру, которая занята выводом на тайловую плоскость по правилам, которые использует VDP – линия тайлов зациклена по горизонтали, столбики – зациклены по вертикали, опираемся на переменные, указывающие точку отображения в видеопамяти по X и Y. Читаем из «её» видеопамяти.
Да, это работает. Я организовал viewport для их системы. Жручий, софтовый, но ведь есть 14мгц. Терпимо жрёт, вернёмся.
Спрайты – 8х16. расположены последовательно. Конверчу один их спрайт в 2 наших 8х8, с координатой на 8 больше для второго по вертикали. Хорошо, у нас спрайтов 85, у них 64, но, блин… :) оказывается – вполне хватает. Игре много спрайтов не нужно, она постоянно управляет очередью вывода. Эмулю.
В общем и целом всё начало работать.
И вдруг, в определённый момент, я замечаю – игра работает, но я не могу перейти на второй уровень. Вис. Виснем. Наглухо.
Ок, отметил. Не то что бы плохо, ребят. ХУЁВО. Но это не единственная проблема сейчас. Пусть и одна из огромных.
Продолжаю уточнение, нахожу некорректируемые мною области, выясняю что это – файнал скрин, правлю, сижу тащусь – читаю о авторах оригинальной версии.
Весь код написал один человек — SHINOBU HAYASHI. Это потрясно.
Но из-за системы — код вывода их финального «скроллера», из примерно 48 байт был заменён — на два.
Ок, ещё одно место которое обнаружено. Но проблема – осталась.
Периодически проявляются странности на карте – что-то новое появляется, явно память меняется. Но блин! – в эмуле всё чётко…
Два вечера поиска.
Два вечера постоянного ежеминутного перетыка карты, перезапуска игры с просмотром – где должен мигать бордер. Здесь – мигает. А тут — не мигает :)
И вот, вдруг увидел.
Картридж загружен в блоки от 0 до #0f. Spg — грузит это всё, в нужные паги.
Но при запуске – включает im 1, и (как я думаю) – отрабатывает прерывание бейсика.
И портит память с #5b00.
Это ужасно :) недокументированная штучка WC.
Буквально: перед глазами стоит ранее виденный код WC – запуск. Ld iy, #5c3a: ld a, #3f: ld I,a: im 1: ei: — я понимаю что 5ая страница с обьектами – ровно здесь. Где находится блок, отвечающий за обьекты на игровом скрине. Их становится очень много. Они забивают память обьектов Мы – виснем.
На реале :)
На эмуле я запускал без WC.
Что ещё остаётся? – звук же, лин. Игра глуха.
Чип имеет 4 канала, три прямоуголки, один – шум.
Да, всё у него относительно АУ – навыворот. 0 – громкий, 15 – глухо.
Те же биты для команд в первом отправленном байте, второй – данные. Привычно для данной системы.
Ну и – 10 бит для частоты :) решаю просто – повышаю октаву в исходнике на 2, для эмулирования – использую две процедуры записи байта в порт. Одна принимает значение и отправляет, вторая – принимает только два, и потом начинается конверсия значений для саундчипа.
Чипа 4, поэтому канал ударных отправил на 2й саундчип, если он есть. Юзайте турбосануд, ребят! :)
В общем, не смотря на такую обширную статью, всё таки все детали разработки я не описал. Выделил только самые эмоционально сильные, самые интересные по методике реализации, самые особенности конверсии.
Подведу итог.
Как работает игра.
Мои процедуры живут в прерывании, в прерывании соника.
Бинарь оригинальной игры постит всё что касается памяти VDP — в отдельный буфер, который для меня выглядит как их видеопамять, в точности относительно тайлов. Спрайты я обрабатываю из очереди, которую формирует игра, и обрабатываю своим особенным образом – для правильного «обратного» вывода.
Графика конвертируется на лету из их слоевого байтового вида в приемлемый – с помощью процедуры конвертации.
Звук – получаем данные выхлопа на SN, конвертируем в данные, подходящие для АУ.
Всё работает на лету.
Это – не эмуляция, ребят :)
Это глубокая конверсия.
Но я приглашаю вас посмотреть как это выглядело, и чем это закончилось – здесь, на гитхабе соника.
Возможно (а я знаю, что есть такие же любители копнуть движки), это к чему-то приведёт.
И, думаю, — приведёт :)
После выпуска РасМаn я начал искать – что ещё есть из аркад, которые были бы очень популярны, и подходили под мои требования для переноса – z80, интересная игра, хотя-бы минимальное техническое описание для разбора кода. Заодно поиск шёл не только по аркадным кабинетам.
Метался я много – смотрел в сторону РС8000, оценивал код игр под 8080, да много чего перебрал.
Оказалось, что «всё не так просто» ;) По аркадам – дичайший зоопарк по оборудованию.
Да, часто линейка игр использует свой стандартный набор оборудования. Но при этом часто это однотипные игры.
В аркадах часто используются по несколько процессоров, и довольно часто — разных типов. Например – 68000 и z80, либо же z80 и z80, один 6502 и т.д. и т.п. Точно так-же – народ не лимитирует себя и в звуке. Использовать несколько АУ, комбинировать АУ и ФМ чипы – это нормально. Использовать второй процессор сугубо для генерации звука – это тоже нормально :) Некоторые аркады используют больше двух процессоров.
Довольно интересно и не привычно – многопроцессорные 8бит системы? Неожиданно!
В результате – я нашёл нечто, что вполне могло сделать мне ненадолго некоторое настроение – galaxian. Клёвая игра, типа. Основана на железе пек-мена, но со своими особенностями: типа область памяти, указывающая на сдвиг строк в экране.
Да, она заработала, начала что-то показывать, но их способ разработки меня раздражал. Писало игру явно несколько человек, и каждый использовал свои подходы к реализации.
В общем, не смотря на то что игра уже отрабатывала основные циклы, строила на экране картинку и прочее – я её забросил.
Потому что – древняк. Потому что – скучно сейчас в это играть. Потому что – не то.
Надо что-то интересное.
Продолжающийся поиск привёл меня к приставкам на z80. Их не так много, и последняя из приставок, использующая z80 как main cpu – оказалась Sega Master System. Не самая продаваемая, но со своей коллекцией хитов.
Я просматриваю их каталоги игр на предмет скачать – вижу пачки платформеров, и вдруг вижу Соника. Хо!
Загрузка бинаря в spg, грузим в эмуль, начинаю проходить – гм, очень даже толковый код, всё продумано. Работаем с адреса 0, используем im 1, юзается rst #28 и подобные непривычные обычному спектрумисту команды :)
При старте очищается область #c000-#dfff, что-то пишется в порты #BF, но далее – начинается инициализация начального цикла, и вызовы, команды, вызовы, команды, команды, переходы …
Но, при этом – код очень хорош. Выглядит отлично – продуманно.
Однако! Отличный вызов.
Чёрт, похоже – это будет интересное путешествие…
Ищу доки. Что за порты? Почему такая память (#c000-#dfff) для переменных?
Оказывается, SMS имеет всего 8к памяти.
Оказывается, SMS имеет пагинг памяти для страниц 0,1,2.
Оказывается, SMS имеет свой видеочип, основанный на популярной тогда микросхеме TMS9918A, но изменённой, и называемой VDP.
И да, картридж с 256к.
Что предлагает их видеочип?
— 16 кб видеопамяти, адресуемой портами
— Сдвиговые регистры (X,Y) для отображения экрана
— тайловый слой, тайлы размером 8х8. Можно флипить X и Y, можно их показывать поверх спрайтов. Набор – до 512 возможных, но увы – меньше. Память 16к общая на всё :)
— 64 спрайта, заданным размером: 8х8 или 8х16.
— 32 цвета из набора 64х, по 2 бита на цвет. 16 цветов – на тайлы, 16 – на спрайты.
— разрешение 256х192
— 16ц на всё
Гм, блин же. Система очень даже легко ложится на возможности конфы, и при этом остаётся ещё очень много доступных ресурсов!
Чо там со звуком? Непонятно. Чип с прямоуголкой, 4 канала, один на шум. Да и ладно, сейчас совсем другие заботы.
Гуглю, много гуглю. SMSPower! отлично собрал доки, реально отлично.
Опыт подсказывает – гугли ещё и с добавлением строки «source». Отличное попадание! Есть отличный разбор исходника с большим проставлением меток и комментариями – гит от Kroc Camen. WOW! SUPERB! Чёрт, всё становится гораздо понятней!
Клонирую репу. Исходник собирается только под асемблер WlaDX. Зверь странный, но интересный. Исходник – собирается. Собранное – работает под эмулем Emulicious.
Пишу благодарственное письмо Kroc, что-то пытаюсь поправить.
Управление памятью – через маппинг. Меняю ld (_RAM_FFFE_), a на call set_page2 и подобные вещи – отлично всё укладывается по байтам.
Начинается очень плотное погружение в игру, да и в их систему вообще.
Но удивительно – асм Ville начинает ругаться – память переписана!
Изучаю его асм, обнаруживаю удивительную фичу – его асм умеет сравнивать подложенный исходник с компилированной версией, и после этого – отмечать изменённые места (команда .background)! Такой фичи я не видел нигде.
Отписываюсь ему, и через пол часа получаю письмо! Этот великолепный финн, работающий в ROVIO, продолжает работу над своим асмом, и постоянно его дорабатывает!
Я показываю ему, что использую версию 2004го года, на что он отвечает что слишком старая версия, собери мол новьё. А оно всё под unix-а, виндового бинаря нет, я в прострации.
И вдруг — Ville идёт к родителям, у которых есть вин 7, ставит там студию, компилит и отправляет мне.
Ville я тебя обожаю! :) Спасибо!
Использовав возможность его асма – отметить места с исправлениями как замещаемые области (.unbackground), я уже знаю – моя область памяти изменяется, остальные чётко фиксированы побайтно. Это надёжно.
Ну и, по большому счёту – лучше поглядите на спецификацию по ассемблеру. Хорош, на самом деле, пусть и не привычен синтаксисом.
На мобилке – пачка док по sms. Чтение доков по системе на ночь и в свободное время. Разбираюсь что она может; какие биты, отправляемые в порты VDP за что отвечают.
Система начинает проясняться.
Задача оказывается отличной. Это будет просто мощно. Работы – много, но вещь – очень достойна.
И ЭТО МОЖНО СДЕЛАТЬ, это переносимо на мою систему.
…
Копаюсь в текущих, насущных деталях. По дороге выясняется, что их 16ц – это вообще не наш 16ц. У них – слои.
Каждый байт из набора 4х байтов – это набор битов для 8ми точек. Бит 7 первого байта, бит 7 второго, бит 7 третьего и 7ой бит четвёртого – это 4 бита (16 цветов) для первой точки. Бит 6 этих четырёх байт – и вторая точка готова.
Класс, блин. Норм чип, конечно. Ну ок, это решаемо. Сконвертим. Пишу.
Итак, их память – 8кб. После #e000 всё свободно. Отлично. Займу всё что нужно :)
Первая попытка по конверсии графики и вывода видна на видео с пати. Я за неделю – разместил всё в памяти, сделал управление нею, сконвертил битпланы, добрался до вывода тайлов, проямолинейно подвигал их биты цвета в нашу палитру, сделал процедуры вывода тайлового слоя на экран, и оно даже что-то начало показывать.
Для пати это было уже что-то, а приготовить хоть ЧТО-ТО для ВАУ на пати — очень хотелось :) Парни-то в курсе что такое Соник!
Все разъехались, я в размышлениях. Предыдущая процедура вывода на экран абсолютно не годилась для работы. Да, это была демонстрация, но это не будет использовано. Я выводил тайлы которые должны были быть на экране — в тайловую память.
Всё не так. Это не работает. Надо размышлять.
Читая как работает система, я прихожу к выводу, что необходимо создать эмуляцию работы VDP.
Система показывает блок из своей тайловой памяти, причём координаты вывода из него заданы по X и Y. Надо повторять их подход.
Организовываю область видеопамяти, в которую пишет игра. Она будет отдельна. Организовываю процедуру, которая занята выводом на тайловую плоскость по правилам, которые использует VDP – линия тайлов зациклена по горизонтали, столбики – зациклены по вертикали, опираемся на переменные, указывающие точку отображения в видеопамяти по X и Y. Читаем из «её» видеопамяти.
Да, это работает. Я организовал viewport для их системы. Жручий, софтовый, но ведь есть 14мгц. Терпимо жрёт, вернёмся.
Спрайты – 8х16. расположены последовательно. Конверчу один их спрайт в 2 наших 8х8, с координатой на 8 больше для второго по вертикали. Хорошо, у нас спрайтов 85, у них 64, но, блин… :) оказывается – вполне хватает. Игре много спрайтов не нужно, она постоянно управляет очередью вывода. Эмулю.
В общем и целом всё начало работать.
Ох уж этот реал!
Периодически я делаю тесты на реальном железе. Эмуль это отлично, но всё должно РАБОТАТЬ.И вдруг, в определённый момент, я замечаю – игра работает, но я не могу перейти на второй уровень. Вис. Виснем. Наглухо.
Ок, отметил. Не то что бы плохо, ребят. ХУЁВО. Но это не единственная проблема сейчас. Пусть и одна из огромных.
Продолжаю уточнение, нахожу некорректируемые мною области, выясняю что это – файнал скрин, правлю, сижу тащусь – читаю о авторах оригинальной версии.
Весь код написал один человек — SHINOBU HAYASHI. Это потрясно.
Но из-за системы — код вывода их финального «скроллера», из примерно 48 байт был заменён — на два.
Ок, ещё одно место которое обнаружено. Но проблема – осталась.
Периодически проявляются странности на карте – что-то новое появляется, явно память меняется. Но блин! – в эмуле всё чётко…
Два вечера поиска.
Два вечера постоянного ежеминутного перетыка карты, перезапуска игры с просмотром – где должен мигать бордер. Здесь – мигает. А тут — не мигает :)
И вот, вдруг увидел.
Картридж загружен в блоки от 0 до #0f. Spg — грузит это всё, в нужные паги.
Но при запуске – включает im 1, и (как я думаю) – отрабатывает прерывание бейсика.
И портит память с #5b00.
Это ужасно :) недокументированная штучка WC.
Буквально: перед глазами стоит ранее виденный код WC – запуск. Ld iy, #5c3a: ld a, #3f: ld I,a: im 1: ei: — я понимаю что 5ая страница с обьектами – ровно здесь. Где находится блок, отвечающий за обьекты на игровом скрине. Их становится очень много. Они забивают память обьектов Мы – виснем.
На реале :)
На эмуле я запускал без WC.
Что ещё остаётся? – звук же, лин. Игра глуха.
Чип имеет 4 канала, три прямоуголки, один – шум.
Да, всё у него относительно АУ – навыворот. 0 – громкий, 15 – глухо.
Те же биты для команд в первом отправленном байте, второй – данные. Привычно для данной системы.
Ну и – 10 бит для частоты :) решаю просто – повышаю октаву в исходнике на 2, для эмулирования – использую две процедуры записи байта в порт. Одна принимает значение и отправляет, вторая – принимает только два, и потом начинается конверсия значений для саундчипа.
Чипа 4, поэтому канал ударных отправил на 2й саундчип, если он есть. Юзайте турбосануд, ребят! :)
В общем, не смотря на такую обширную статью, всё таки все детали разработки я не описал. Выделил только самые эмоционально сильные, самые интересные по методике реализации, самые особенности конверсии.
Подведу итог.
Как работает игра.
Мои процедуры живут в прерывании, в прерывании соника.
Бинарь оригинальной игры постит всё что касается памяти VDP — в отдельный буфер, который для меня выглядит как их видеопамять, в точности относительно тайлов. Спрайты я обрабатываю из очереди, которую формирует игра, и обрабатываю своим особенным образом – для правильного «обратного» вывода.
Графика конвертируется на лету из их слоевого байтового вида в приемлемый – с помощью процедуры конвертации.
Звук – получаем данные выхлопа на SN, конвертируем в данные, подходящие для АУ.
Всё работает на лету.
Это – не эмуляция, ребят :)
Это глубокая конверсия.
Но я приглашаю вас посмотреть как это выглядело, и чем это закончилось – здесь, на гитхабе соника.
Возможно (а я знаю, что есть такие же любители копнуть движки), это к чему-то приведёт.
И, думаю, — приведёт :)
4 комментария
но трип-репорт прочесть было интересно!
а разогнавшись, вылететь с экрана секунд на несколько — это и в оригинале такое было?