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

Загружаем "PRES" в Ghidra по известному ранее адресу 0x9000, добавляем области памяти

в карту памяти
в карту памяти

Точка входа нам известна из прошлой статьи, это 35074 или $8902, смотреть будем в "декомпилированный" код, он компактнее, хотя и не всегда соответствует действительности

void main(void)

{
  undefined *puVar1;
  short in_DE;
  byte (*paabVar2) [8] [32];
  byte *pbVar3;
  
  Set_Interrupts_and_Run();
  CLS();
  Clean8000to9000and5E00to6200();
  Print_msg(&txt_FOR_CASSETTE);
  Colors_Fading();
  Print_msg(&txt_PRESENTS);
  Colors_Fading();
  Sprite(0,7,10);
  Sprite(1,10,0xe);
  Print_msg((HDmessage *)&txt_Delay);
  Colors_Fading();
  FUN_ram_9b7c(in_DE);
  DAT_ram_ac2c = 200;
  DAT_ram_ac2d = 0x10;
  DAT_ram_ac41 = 0xe0;
  DAT_ram_ac42 = 0x10;
  DAT_ram_ac56 = 0xf0;
  DAT_ram_ac57 = 0x10;
  DAT_ram_ac6b = 200;
  DAT_ram_ac6c = 0x10;
  do {
    FUN_ram_9a4d();
    BYTE_ram_9620 = 1;
    halt();
    halt();
  } while (0x27 < DAT_ram_ac2c);
  Print_msg((HDmessage *)&txt_Delay);
  Colors_Fading();
  FUN_ram_9b8f(in_DE);
  DAT_ram_ac2c = 0;
  DAT_ram_ac2d = 0x28;
  DAT_ram_ac30 = 1;
  DAT_ram_ac41 = 0;
  DAT_ram_ac42 = 0x28;
  DAT_ram_ac45 = 1;
  DAT_ram_ac6a = 0xfd;
  DAT_ram_ac55 = 0xfd;
  do {
    FUN_ram_9a4d();
    BYTE_ram_9620 = 1;
    halt();
    halt();
  } while (DAT_ram_ac40 != -3);
  Print_msg(&txt_START_TAPE);
  pbVar3 = &DAT_ram_b192;
  paabVar2 = SCR_BITS;
  puVar1 = &DAT_ram_1b00;
  do {
    *(byte *)paabVar2 = *pbVar3;
    paabVar2 = (byte (*) [8] [32])((short)paabVar2 + 1);
    pbVar3 = pbVar3 + 1;
    puVar1 = puVar1 + -1;
  } while (puVar1 != (undefined *)0x0);
  disableMaskableInterrupts();
  setInterruptMode(0);
  enableMaskableInterrupts();
  return;

Нас интересуют Print_msg и Sprite. Print_msg принимает ссылку на адрес комбинированной строки в регистре HL

        ram:9a9c       LD                     HL,txt_FOR_CASSETTE
        ram:9a9f       CALL                   Print_msg
        ram:9aa2       CALL                   Colors_Fading
        ram:9aa5       LD                     HL,txt_PRESENTS
        ram:9aa8       CALL                   Print_msg
        ram:9aab       CALL                   Colors_Fading

Текст может содержать в себе заголовок со всем необходимым

и даже больше
и даже больше

В тексте могут содержаться маркеры, которые могут задать 1 - координаты на экране для вывода сообщения, 2 - цвет, как фона так и текста, стандартный байт аттрибута, 3 - размер шрифта, сообщение может выводиться с увеличением высоты символа в x раз, 6 - задержка, 0 - закончили с текстом. Знакогенератор находится по адресу 0xAC7E

красота красивая
красота красивая

Со спрайтами чуть проще, координаты задаются при вызове функции, координаты измеряются не в точках а в знакоместах, как у текста, скорее всего, чтобы не заморачиваться с клэшингом. Необходимая нам процедура Sprite принимает номер спрайта и координаты в регистрах A, B, C

        ram:9aae       LD                     A,0x0
        ram:9ab0       LD                     B,0x7
        ram:9ab2       LD                     C,0xa
        ram:9ab4       CALL                   Sprite
        ram:9ab7       LD                     A,0x1
        ram:9ab9       LD                     B,0xa
        ram:9abb       LD                     C,0xe
        ram:9abd       CALL                   Sprite

Адреса спрайтов получаются складыванием базового адреса 0xAA9c и смещение из таблицы смещений по адресу 0x9889

        ram:9889       ushort[3]
           ram:9889 [0]                0h,   146h,   190h

, размер спрайта содержится в начале самого спрайта, размер тоже в знакоместах

        ram:aa9a       HDRsprite
           ram:aa9a                 db        Ch                      width
           ram:aa9b                 db        3h                      height
        ram:aa9c       ??                     0Fh
        ram:aa9d       ??                     F0h
        ram:aa9e       ??                     FFh

Colors_Fading осуществляет "красивую" очистку экрана, с переливающимися цветами. Вроде всё рассказал... Далее будет разбор файла самой игры, или сначала загрузчик переделаю, ещё не решил. Ниже текстовые сообщения, спрайты в заголовке статьи.

начало
начало
середина
середина
финалочка
финалочка

1 часть

2 часть

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


  1. kmatveev
    14.08.2025 06:20

    Круто.

    Дизайнер шрифта - чёртов гений. В клетку 8*8 вставить буквы, у которых толщина линий 3 пикселя, и оно всё равно отлично читается.