Paprium: почему я считаю его посредственной поделкой, раздутой маркетингом (мое субъективное мнение, прошу это учесть)

—

от автора

Если отбросить многолетнюю истерию с предзаказами, пафосные трейлеры и культ «секретного железа», перед нами довольно заурядный битемап. Да, картинка на статичных скриншотах выглядит сочно, но стоит нажать Start — и иллюзия начинает рассыпаться.

Вот из чего на самом деле состоит эта «революция»:

  • Геймдизайн на уровне середняков из 90-х. По динамике, чувству удара и балансу Paprium не дотягивает до Streets of Rage 2 1992 года, не говоря уже о Comix Zone или Alien Soldier. Анимации местами дерганые, хитбоксы живут своей жизнью, а затянутые волны однотипных врагов утомляют.

  • Маркетинговый пузырь. Потенциальным покупателям годами продавали легенду про «80 мегабит чистой мощи» и таинственный сопроцессор Datenmeister, без которого бедная Сега якобы задохнулась бы от такой невероятной графики. На деле всё банальнее: внутри картриджа обычный 32-битный ARM-микроконтроллер и довольно сильная для одноигрового картриджа CPLD.

  • Железо ради защиты, не ради игры. Даже легендарный SVP в Virtua Racing честно молотил 3D-математику и конвертировал полигоны в тайлы для родного VDP, потому что Motorola 68000 такое бы не потянула. Здесь же у нас обычный 2D-битмап. Никакой «графической магии» Datenmeister не творит — картинку рисует VDP. А CPLD и ARM в картридже занимались декомпрессией, крутит внешний аудиопоток в обход консоли и городит лютую обфускацию шины, чтобы игру не сдампили.

  • Диагноз. Эта маркетинговая шелуха окончательно осыпалась в конце октября 2026 года, когда вышел патч Paprium MD. Энтузиасты просто выкинули весь этот зоопарк из ARM и хитрого маппера, пересадили звук на родной Z80 и уложили игру в обычный 15-мегабайтный ROM. И внезапно выяснилось: сама Mega Drive образца 1988 года прекрасно переваривает эту игру без костылей (если бы ещё YM в SEGA был бы 16-битный DAC, то разницы вообще бы не ощущалось).

Как это вообще работает:

Оригинал Paprium работает по принципу «тонкого клиента». Сама приставка Sega Mega Drive здесь выступает в роли видеоадаптера и контроллера ввода, а вся вычислительная работа перенесена внутрь картриджа на сопроцессор Datenmeister.

  • Общение через «почтовый ящик» (Dual-Port CPLD MAX10 RAM + SDRAM). Процессор консоли Motorola 68000 не имеет прямого доступа к сжатым ресурсам. Вместо этого он общается с картриджем через область общей памяти ($0-$1FFF DPRAM, $0x2000-$BFFF RO RAM, $C000-$FFFF Increments RAM, каждое чтение сдвигает pointer распаковщика на 2 байта) . Чтобы «отдать приказ», 68000 записывает аргументы в рабочие ячейки (например, 0x1E10–0x1E28) и отправляет код команды в управляющий регистр 0x1FEA. Пока чип занят, он выставляет биты занятости в статусном регистре 0x1FEA.

  • Аппаратный графический конвейер (DPRAM + SDRAM + VDP DMA). Внутри картриджа установлена SDRAM. По командам с приставки (0xAE — начало кадра, 0xAD — добавить объект, 0xAF — завершить кадр) ARM сопроцессор:

    1. Распаковывает тайлы алгоритмами LZ+RLE и LZO в SDRAM.

    2. Управляет кэшем слотов видеопамяти (VRAM) и при необходимости масштабирует графику (команды 0xF4/0xF5).

    3. Формирует готовую таблицу спрайтов (SAT) и готовые пакеты команд для VDP DMA. Приставке остается перегнать готовые данные в видеочип через окно потокового чтения 0xC000–0xFFFF и область 0x0-0xBFFF.

  • Аудиокодек (BGM + 8 каналов SFX). Штатные звуковые чипы Mega Drive (YM2612 и SN76489) в музыке не участвуют. Внутри картриджа работает программный декодер и 8-канальный микшер звуковых эффектов с поддержкой панорамирования, изменения высоты тона и стерео-эха. Готовый микс подмешивается напрямую на аудиовход слота картриджа.

Психология долгостроя: как покупателя заставили платить за DRM:

История разработки Paprium — это мастер-класс по манипуляции ожиданиями ретро-сообщества. Авторы годами подогревали ажиотаж, перенося релиз, рассказывая о «невозможных 80 мегабитах чистой мощи» и культивируя образ секретной технологии, которую «невозможно сэмулировать». Это чистая игра на психологии коллекционера: Вам продают не просто игру, а «артефакт» с уникальным чипом внутри.

Дефицит, закрытые предзаказы и мифы о «сгорающих при попытке дампа платах» создают вокруг посредственного битемапа ореол элитарности.

Тест №1. Запускаем оригинал на ПК (порт Datenmeister в Genesis Plus GX)

Чтобы детально изучить, как игра общается с картриджем, я портировал эмуляцию сопроцессора Datenmeister в эмулятор Genesis Plus GX.

Обработчик команд сопроцессора (регистр 0x1FEA):

static void paprium_cmd(uint16_t raw_data) {    uint8_t cmd = raw_data >> 8;    uint8_t arg = raw_data & 0xFF;    uint16_t resp = 0;    // Set BUSY 0x1FE4 / 0x1FE6    ram_w16(0x1FE4, ram_r16(0x1FE4) | 0x0004);    ram_w16(0x1FE6, ram_r16(0x1FE6) | (1 << 14));    switch (cmd) {    case 0x00:        resp = (arg == 0xAA) ? 0x00FF : 0x0000;        break;    case 0x81: // Init / Reset        ppm_vram_set_budget(0);        ppm_obj_reset();        break;    case 0x84: // Mapper        memcpy(ppm.ram + 0x8000, cart.rom + 0x8000, 0x8000);        break;    case 0x88: // Audio settings        ppm.audio_flags = arg;        ppm.ram[0x1801] = arg & 0x01;        ppm.ram[0x1800] = ((arg & 0x01) ? 0x80 : 0x00) + ((arg & 0x02) ? 0x40 : 0x00);        break;    case 0x8C: // Play BGM    {        uint8_t track = arg & 0x7F;        if (ppm.bgm_tracks_base_addr) {            ppm_unpack(ppm_bgm_addr(track), ppm.bgm_unpack_addr);        }        if (track != 0) {            paprium_load_mp3(track, 1);        }        else {            ppm.music_track = 0;        }    }    break;    case 0x8D: // BGM settings        if (arg == 0 || arg == 8) {            ppm.music_track = 0;        }        break;    case 0xAD: // Add object to draw list        if (ppm.draw_list_ptr < ppm.draw_list + PPM_OBJECTS_COUNT) {            *ppm.draw_list_ptr++ = arg;        }        break;    case 0xAE: // Frame start        ppm_obj_frame_start();        break;    case 0xAF: // Frame end (AF01 = обычный кадр, AF02 = кадр со скейлингом)        ppm_obj_frame_end(arg);        break;    case 0xB0: // Sprite init        memset(ppm.ram + 0x1F20, 0, 14 * 8);        break;    case 0xB1: // Sprite pause        if (ram_r16(0x1F18) == 0) {            memset(ppm.ram + 0xB00, 0, 8);        }        break;    case 0xC6: // Setup data tables        ppm_setup_data(            ram_r32_swapped(0x1E10),            ram_r32_swapped(0x1E14),            ram_r32_swapped(0x1E18),            ram_r32_swapped(0x1E1C),            ram_r32_swapped(0x1E20),            ram_r32_swapped(0x1E24),            ram_r32_swapped(0x1E28)        );        break;    case 0xC9: // BGM volume        ppm.music_volume = arg;        break;    case 0xCA: // SFX volume        ppm.sfx_volume = arg;        break;    case 0xD1: // SFX play        paprium_sfx_play(arg);        break;    case 0xD2: // SFX stop        paprium_sfx_stop(arg);        break;    case 0xD3: // SFX loop        paprium_sfx_loop(arg);        break;    case 0xD5: // SFX stop all        paprium_sfx_stop(0xC0);        break;    case 0xDA: // Unpack to SDRAM    {        uint32_t dst = ram_r16(0x1E10);        uint32_t src = ((uint32_t)ram_r16(0x1E12) << 16) | ram_r16(0x1E14);        ppm_unpack(src, dst);        ppm.sdram_read_ptr = dst;    }    break;    case 0xDB: // Set SDRAM read pointer        ppm.sdram_read_ptr = ram_r32_swapped(0x1E10);        break;    case 0xDF: // EEPROM / SRAM read    {        uint16_t offset = ram_r16(0x1E10);        if (arg >= 1 && arg <= 4) {            memcpy(ppm.ram + offset, sram.sram + ((arg - 1) * 0x780), 0x780);        }    }    break;    case 0xE0: // EEPROM / SRAM write    {        uint16_t offset = ram_r16(0x1E12);        if (arg >= 1 && arg <= 4) {            memcpy(sram.sram + ((arg - 1) * 0x780), ppm.ram + offset, 0x780);        }        ram_w16(0x1FE6, ram_r16(0x1FE6) & ~((1 << 8) | (1 << 9)));    }    break;    case 0xE7: // MegaWire fake ack        ram_w16(0x1FE6, ram_r16(0x1FE6) | (1 << 5));        ram_w16(0x1C00 + 0x10, ram_r16(0x1E10) + 16);        break;    case 0xEC: // VRAM block budget        ppm_vram_set_budget(ram_r16(0x1E12));        break;    case 0xF2: // Unpack block (sprite test menu)    {        uint16_t blk = ram_r16(0x1E10);        ppm_unpack(ppm_block_addr(blk), 0x9000);        ppm_unpack(ppm_block_addr(blk), 0x9200);        ppm.sdram_read_ptr = 0x9000;    }    break;    case 0xF4: // Unpack scaling stamp        ppm_unpack_internal(ram_r32_swapped(0x1E10), 0, 1);        break;    case 0xF5: // Rescale stamp        ppm_stamp_rescale(            ram_r16(0x1E10),            ram_r16(0x1E12),            ram_r16(0x1E14),            ram_r16(0x1E16)        );        break;    default:        break;    }    // Снимаем флаг занятости и записываем ответ в 0x1FEA    ram_w16(0x1FE4, ram_r16(0x1FE4) & ~0x0004);    ram_w16(0x1FE6, ram_r16(0x1FE6) & ~(1 << 14));    ram_w16(0x1FEA, resp & ~0x8000);}

Смотрим, как доказательство концепта: https://archive.org/details/ppm-emu

Как запустить: скачиваем, распаковываем, запускаем ppm.cmd (windows).

Что я хочу сказать этим?

На борту CPLD MAX10 10M08 , 64к быстрой памяти внутри, 8000 логических блоков, 18×18 бит 16 независимых аппаратных блоков умножения, процессор CORTEX M-4, SDRAM и FLASH, при этом Z80 в консоли стоит, никаких вращений, только скалинг, распаковка и аудио! Динамическое освещение казалось бы тема, нет такого, вращение, 3D модели, нет такого, просто копирование того что распаковал ARM на экран через CPLD, с таким подходом SEGA CD выглядит супер мегахит, который не возможно реализовать в 90-х!

Тест №2. Оригинальный дамп на IVD6 MAX.

Теперь от программной эмуляции переходим к живому железу.

Берем оригинальную Sega Mega Drive, флеш-картридж InviteDRIVE v6 MAX и запускаем непатченный образ Paprium. Чтобы не тратить 2Gb памяти на карте, соберем паприум в пакованный образ для аппаратных картриджей SCDX с помощью вот этой утилиты: https://ivd6max.ramfactory.com/scdx.html.

Обратите внимание на звук на стартовой заставке: с первых секунд поверх интро начинает играть трек из меню выбора персонажей (*90’s Acid Dub Character Select*), чего в оригинале не было.

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

Тест №3. Запуск 15-мегабайтного хака без спецчипа.

А теперь заливаем октябрьский патч Paprium MD на 15 мегабайт, из которого энтузиасты полностью вычистили зависимость от Cortex-M4 и внешнего аудиокодека.

Стандартное адресное пространство Sega Mega Drive ограничено окном в 4 мегабайта. Чтобы консоль увидела все 15 МБ разжатой графики и кода, в дело вступает аппаратный маппер банков SSF2 (Super Street Figher 2) памяти внутри ПЛИС картриджа.

И вот здесь всё встает на свои места: FPGA картриджа переключает банки памяти. Штатный Motorola 68000 сам справляется с переброской тайлов в VDP.

Звук полностью переехал на родные Z80 и YM2612: да, из-за ограничений ЦАП самого YM2612 он звучит проще, чем внешний поток с картриджа, но при этом абсолютно аутентично для классической Mega Drive.

Резюме История с Paprium — показательный пример того, как громкий маркетинг, искусственный дефицит и «секретный чип под эпоксидкой» могут годами продавать весьма посредственный битемап под видом технологической революции.

Когда же с проекта сняли шелуху в виде Cortex-M4 и MAX 10, выяснилось, что обычная Sega Mega Drive 1988 года легко тащит этот 15-мегабайтный объем сама — а при желании и внешний аудиопоток сверху накинет.

Поэтому для меня PAPRIUM это обман.

Еще раз повторюсь, это мое исключительно субъективное мнение! Я не настаиваю на нем, просто мнение.

За сим позвольте откланяться, С уважением, и наилучшими пожеланиями, наилучшего дня!

Спасибо!

ссылка на оригинал статьи https://habr.com/ru/articles/1107694/