Изначально я не планировал делать демо на Chaos Constrictions 2018, однако за 2-3 недели до cc понял, что с пустыми руками идти на демопати никак нельзя, и решил написать небольшую демонстрацию для 386/EGA/DOS.

Скомпилировав в Turbo-C под DOS свою либу AnotherGraphicsLibrary, которая идеально ложиться в битплановую структуру EGA режима, я разочаровался, от тормозов, прежде всего тормозов EGA. Демо в том виде, в котором я хотел бы его видеть, за этот весьма ограниченный срок, сделать было невозможно.

Однако сдаваться и не делать что-либо, я уже не мог. И тут я вспомнил, что давно хотел принять участие в ZX-Spectrum конкурсах демо. А так, как за последний год у меня появилось целых два 48k реала, я мог получить определенное удовольствие от создания демо. К слову — для меня самое главное в написании демо это именно тестирование на реале, эмульгаторы не дают такого наслаждения от процесса, уж очень это замечательное чувство, когда после очередного изменения в коде ты закачиваешь демо на реал, и видишь как настоящая железка тасует байтики в памяти, отрисовывая эффект.

Поскольку из реалов у меня только 48k, то и демо я решил сделать для 48k. А из-за ограниченности сроков и отсутствия каких-либо наработок, выбор пал на создание 1k intro(демо объёмом всего 1 килобайт, или 1024 байта).

Последний раз z80 asm я тыкал в EmuZWin — замечательном эмуляторе со встроенным ассемблером. Но к сожалению EmuZWin на чем-либо выше Windows XP не работает, либо глючит.
Рассмотрев различные варианты остановился на связке программ Unreal+sjAsm+Notepad++, которые, на мой взгляд, по удобству сильно проигрывают EmuZWin, но в отличие от него живы.

Во время написания этого интро я вел, прямо в исходниках, лог разработки, по мотивам которого написан дальнейший текст:

Hello World!

Что надо писать первое, имея практически нулевой опыт в z80 asm? Правильно, вывод спрайта 5x5 знакомест или 40x40 пикселей, для одного из эффектов (по иронии, в дальнейшем, для того чтобы влезть в 1k эта недоделанная часть была выкинута из интро).

Поразительно, но это было довольно просто сделать с нуля, используя наперед сгенерированную табличку адресов строк с помощью Down HL.

Ох, индексные регистры, какие же они удобные, но какие меееедленные, буквально выжирают такты. Пришлось выкинуть их использование из кучи мест.

Еще здесь, в самом начале, я наткнулся на невероятные глюки sjAsm, точнее его последней версии. Дизасм в Unreal показывал абсолютно бредовую последовательность команд. Скачал предпоследнюю версию — с ней уже можно было хоть как-то жить.



Понятное дело, что сколько-нибудь адекватное кол-во заранее нарисованных спрайтов в 1k не засунуть, поэтому я решил сгенерировать их динамически. Причем не абы как, а нарисовать с помощью полигонов.

Поэтому второй процедурой, которую я написал, стала процедура рисования треугольника. По большей части это было портирование своего-же кода, написанного на Си. С единственным глобальным отличием от Си версии — сначала генерируются сканалйны полигона, а только потом он рисуются по этим сканлайнам.

После высокоуровневых языков, получаешь определённое наслаждение от jr aka goto:

.sort_me_please:
  ld de,(tr_x2)
  ld bc,(tr_x0)
  ld a,d
  cp b
  jr nc,.skip1
  ld (tr_x2),bc
  ld (tr_x0),de
.skip1:
  ld de,(tr_x1)
  ld bc,(tr_x0)
  ld a,d
  cp b
  jr nc,.skip2
  ld (tr_x0),de
  ld (tr_x1),bc
  jr .sort_me_please
.skip2:
  ld de,(tr_x2)
  ld bc,(tr_x1)
  ld a,d
  cp b
  jr nc,.skip3
  ld (tr_x2),bc
  ld (tr_x1),de
  jr .sort_me_please
.skip3:

Я был немного шокирован, тем, что у меня вышло в разумное время написать работающую draw_triangle на z80 asm, рисующую полигон пиксель в пиксель и без дыр при стыковке полигонов.


Hello triangles!

Частицы



Из-за наличия генератора табличкек строк экрана, я написал довольно кривую и медленную процедуру вывода точки, использующую эту табличку. Процедура имеет две точки входа — просто инверсия пикселя, и инверсия пикселя с закрашиванием его INK-а+BRIGHT+а цветом указанном в одном из регистров.

На этапе создания эффекта с частицами обнаружил что пример со структурами из примеров в wiki sjAsm просто не работает. Гугление вывело на тему с сайта zx-pk.ru, где описана эта проблема, и нет ее решения — ха, отлично — еще один глюк.

Решил сделать все четко — обновление координат независимо от отрисовки, по прерыванию. Ага… плюс дохрена байтов для генерации таблицы прерываний.

Частиц на этом этапе было немного, и они едва влезали в фрейм — это к слову о медлительности моей процедуры вывода точки %) Но использование общей таблицы со спрайтами, не давало мне ее выкинуть, и взять готовую, т.к. это сильно экономило место на необходимости только одного генератора таблиц. Да и моя любовь к велосипедам тоже :)

Слишком мало частиц… увеличил их количество, но теперь отрисовка разжирела до двух фреймов.


Тестирование на Peters WS64, который я добыл на прошлом cc и починил этой зимой :)

Кстати, уже на этом этапе точки превратились в жирные горизонтальные точки 2:1, как на Commodore 64. Вышло это из-за изначально малого кол-ва частиц, и моей неудовлетворённостью тем, что они были довольно незаметны при прогоне на реале. Решил проблему заменой таблички

db 128,64,32,16,8,4,2,1;

на

db 192,192,96,24,12,6,3,3;

что ухудшило точность позиционирования и сделало полет чуточку дерганым, но увеличило заметность. Тут на руку также сыграло еще и то, что частицы падали сверху вниз — по вертикали их размазывало зрение.

Частицы кстати падают каждая со своей случайной скоростью, а для хранения координат по Y используется два байта.

Спрайты

Выкинул недоделанный кусок части со спрайтами, поняв что не уложусь в 1k с ним.

Кроме того, уже ощущалась нехватка места, поэтому вспомнил про замечательную статью Интроспека про пакеры, выбрал zx7 в качестве пакера, что дало экономию примерно в 110 байт. Кстати возможно кто-то знает более подходящий пакер для 1k интро?

Chaos Constructions



Поскольку у меня уже бала процедура вывода полигона, мне показалось крутой идеей разбить лого cc на полигоны и вывести на экран их друг за другом.

Написал некоторый тестовый код, выводящий несколько полигонов — все работало как я и задумал — отлично.

Для проверки того, влезет или нет моя задумка в 1k, нагенерировал некоторое кол-во рандомных полигонов, по прикидкам, достаточное кол-во для логотипа, и загнал в исходники. Скомпилировал, и убедился что — отлично — интро, в этом виде, влезает в лимит 1024 байта.


Лайф фото, узнаете девайс на столе? :)))

Решил еще раз протестировать полуфабрикат интро, уже с полигонами, и пакером, загрузил на реал и… получил сброс. Впервую очередь я стал грешить на то, что где-то забыл проинициализировать память, от чего, там, где на эмуляторе 0x00 и все отлично работает, на реале мусор, вызывающий сброс.

Ничего лучше, для нахождения проблемного места, чем метод половинного деления и di halt я не смог придумать.

Провозился со сбросом на реале в течении двух часов, локализовать глюк никак не выходило…
Как оказалось, дело было не в моем коде, дело было в включённом улучшайзере звука на телефоне с которого я грузил WAV-ки. Улучшайзер из потока битов в WAV файле генерировал поток бреда.

Как только я отключил его все волшебным образом заработало.

Обрисовал логотип в графическом редакторе errorsoft greenpixel, разбив его на кучу треугольников, и загнал вручную координаты в исходники. Запихнув лого Chaos Constructions полностью и запустив на реале — порадовался — выглядело довольно не плохо.


Первое отображение лого на реале

Однако рандомных полигонов я напихал слишком мало, и на реальном лого, произошел выход за лимит 1k на 150 байт. И это при том, что эффект частиц был все еще не доделан, а переход между частями был резкий.

Лечь спать в этот день, из-за возни с глюками, вышло аж в 8 часов утра 8)

И да, я пытался оптимизировать размер, храня координаты и индексы вершин отдельно, но это сильно не нравилось пакеру, от чего размер только увеличивался.

Финал



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

fake_points1:
  db 1,2,4,8,16,32,64,128; 1 ch
fake_points2:
  db 32,8,128,2,16,1,64,4; 2 ch
normal_points:
  db 128,64,32,16,8,4,2,1; 3 ch

Что дало прикольный эффект увеличения детализации отрисовки логотипа, или изначальной заблюренности и постепенного увеличения резкости.

И наконец, я сделал окончательную версию со всеми переходами, выкинув при этом кучу всего. В процессе нашел глюк в процедуре рисования треугольника — если у двух вершин координаты по Y одинаковые, то треугольник рисуется криво (похоже деление на 0 при вычислении dx), обошел временным хаком.


Тестирование окончательной версии на Leningrad 48

Оптимизация размера


Двузначные цифры — это «лишние байты»

94 лишних байта…

Пришла пора вырезать «культурное» сохранение/восстановление регистров у процедур на входе/выходе, далеко не везде это надо, а память жрет.

86 байтов…

Протестировал на реале — работает! Отбил еще немного памяти, попутно пофиксив баг с делением на 0 — 63 байта!

57 байт…

Добавил зацикливание.

random_store:
start:

Зацикливание кстати сделано на уровне распаковки, т.к. в качестве источника энтропии для ГСЧ использовались несколько байтов из кода инициализации (для экономии места), которые в процессе работы первой части портил ГСЧ. Поэтому для зацикливания, после окончания интро стоит ret, ну, а дальше — еще одна распаковка и переход к распакованному коду…

Избавиться от последних 48 байт не удалось никак, пришлось выпилить обработчик прерывания, но УРА! Запихал! Даже 1 лишний байт остался.

А раз нет прерываний, то можно забить на фреймовость, да и сложно увидеть сечение луча на одном пикселе в первом эффекте, поэтому увеличил кол-во частиц на глаз, с компромиссом между скоростью и зрелищностью.

Еще сильнее ужал, тупо переносом кода и данных из одного места в другое, помогая пакеру. Что заняло определенное время :)

Это освободило около 10 байт, в которые я засунул пародию на звук. Кхк, кхе, звук — это в некоторых местах, на слух вставленное:

  ifdef UseSound
  ld a,d
  and #10
  out (#FE),a     
  endif

Я не стал «прибивать гвоздями» звук, а сделал дефайн, получив таким образом две версии интро, со звуком и без. В ту, что без звука, в «лишние» байты запихал

db 'e','r','r','o','r'

Собрал trd и tap, и залил все это на сайт cc.

Ура — я участвую в демопати!

Послесловие

Со звуком вообще забавно получилось, кто-то на патиплейсе говорил про «четкий звук», кто-то странно на меня смотрел, а на pouet я обнаружил следующее:



И это:



В общем, так я и не понял, понравился кому-либо 10-ти байтный звук или нет :)

И последнее — обидно что конкурс 1k в этом году так и не состоялся, работа на мой взгляд получилась достойная, но с 640k соревноваться сложно, а очень хотелось побороться.

Пишите демки, пишите 1k!

А вот и то, что в итоге получилось(пс, берегите уши):



Версия без звука:

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


  1. tormozedison
    30.08.2018 23:11

    Да очень даже ничего там звук.


  1. Smayliks
    30.08.2018 23:23

    Очень понравилась фотка, где процессор «магнитофона» с программой раз в 100-200 быстрее самого компьютера. ;-)

    P.S. Ну и по оперативке «слегка» выигрывает, да.


    1. tormozedison
      31.08.2018 09:52

      Только не смейтесь: одно время были популярны плееры, где процессом «рулило» ядро, совместимое с Z80 и работающее на 20 мегагерцах.


      1. engine9
        31.08.2018 09:59

        Кассетные плееры?


        1. tormozedison
          31.08.2018 11:35

          Нет, MP3, начало двухтысячных.
          Кассетники с микропроцессорным управлением, впрочем, тоже были, но там четырёхбитных ядер хватало.
          Вильма-100-стерео особняком, там 16-битный.


      1. Smayliks
        31.08.2018 12:37

        Ну а почему нет? Если бы мне сейчас понадобилось сделать электронику/управление на бобинник, я бы тоже поставил stm32, который быстрее Z-80 в 10 и более раз ;-)


    1. namikiri
      31.08.2018 13:42
      +2

      Не могу не отметить также оригинальный способ передачи программ — посредством голосовых сообщений в Telegram.


      1. Smayliks
        31.08.2018 14:09

        Некасательно этой фотки, на iPad/iPhone действительно легче передать через телеграмм/ё-мыло/етц, чем городить огород с айтюнсами. Хотя и ПК и планшет/телефон в одной комнате.


        1. tormozedison
          31.08.2018 16:04

          Наиболее рациональный способ с точки зрения занимаемого файлом места — приложение tapDancer. Вместо перекодировки tap-файла в wav — проигрывание tap на лету.


          1. Smayliks
            31.08.2018 17:09

            Для iPad/iPhone? В AppStore не нашёл, если это касательно моего комментария. А если вообще, то не знаю, андроид-девайса нет.


            1. rt3879439
              31.08.2018 17:12

              Его не так давно выпилили из appstore, к сожалению.


    1. Jenix
      31.08.2018 16:07

      кхм.
      ZX — 3,5 МГц 8 бит. 2 такта сложение.
      средний смарт 1 ГГц — 4 ядра, 32 бита, 2команды/1 такт.

      Я бы сказал, что смарт быстрее чем ZX не менее чем в
      1000М х 4я х 2к/т х 32бит / 3,5 * 8 * 0,5к/т = 18 285 раз. )
      Это минимум.


      1. beeruser
        31.08.2018 19:34

        ZX — 3,5 МГц 8 бит. 2 такта сложение.

        4 такта


        1. Jenix
          31.08.2018 20:34

          Т.е. почти 40 тысяч раз.


  1. Pyhesty
    31.08.2018 00:05

    =) мне очень понравилась статья) подробненько)
    отдельное спасибо за ссылку на пакеры!
    ps: демо очень достойное своего объёма )
    «музон» тем более =)
    pss: ностальджи )


  1. gban
    31.08.2018 03:44

    load ""
    пшшшш...


    1. tormozedison
      31.08.2018 11:34
      +1

      Сначала «ииииииии», потом «пшик», потом опять «иииитиии», и только потом «пшшшш».


      1. Smayliks
        31.08.2018 12:42

        А это точно не 33600, а программа? ;-)


        1. tormozedison
          31.08.2018 16:06

          Точно. Тон для настройки на скорость магнитофона, имя файла, снова тон, сам файл.


        1. Jenix
          31.08.2018 20:45

          1. Smayliks
            31.08.2018 21:33

            О, спасибо, как-то пропустил.


  1. iga2iga
    31.08.2018 05:30

    Вообще экран спекки можно представить и как линейное пространство 2048х24 пикселей. Ну или 256х3 знакоместа (которые в свою очередь 8х8 пикселей). Интересно, но этот DOWN_HL я почти до сих пор помню наизусть, т.к. это важнейшая часть рисования спрайтов, а особенно «указателя мышки» в любой программке для спекки. Ну и вторая важнейшая часть это от 65000 до 72000 тактов за которые надо успеть сделать всё… Как же я тогда мечтал о 7 или еще лучше о 14 МГц…


  1. Dioxin
    31.08.2018 07:48

    «Ох, индексные регистры, какие же они удобные, но какие меееедленные, буквально выжирают такты. Пришлось выкинуть их использование из кучи мест.»
    PUSH POP only!


  1. CoolCmd
    31.08.2018 10:31

    а частицы в начале демки крутятся по часовой стрелке или наоборот? :)


    1. Error1024 Автор
      31.08.2018 14:55

      Слева направо :)


      1. Oxyd
        01.09.2018 02:23

        Как-то так?


  1. rt3879439
    31.08.2018 11:53

    Куда больше меня поразила дема на АОНе.


    1. Igor_O
      31.08.2018 13:53
      +1

      Ну формально, почти все АОНы были на Z80. А Z80 — это весьма крутой процессор, для своих 8 бит, а если еще и на 3.5 МГц…


      1. tormozedison
        31.08.2018 16:06

        Потом перевели на 8051, блоки питания резко такими холодными стали.


  1. Javian
    31.08.2018 12:00

    если вывести звук не на пьезо, а на динамическую головку, то звук будет мягче.


  1. dmnBrest
    31.08.2018 13:19

    Да, было время! В каждом дворе были специалисты способные писать такие демо. Сам помню принимал участие в соревновании местных умов по созданию демо в 100 байт. Жаль что у большей части нынешней аудитории ничего кроме недоумения данная статья не вызовет. Не знал что СС еще проводится. Спасибо за позитив!


    1. frog
      31.08.2018 16:23

      Ну, в принципе, одних только 256 байтных интр в этом году на CC было аж 27 штук для разных платформ. Так что про «были» — это как-то неактуально звучит :)


  1. vheinitz
    31.08.2018 13:20
    -1

    когда я читал о заговоре Римского Клуба против научно-технического прогресса я посмеивался. А вот теперь и подтверждение. Последнее время завалили статьями, как сделать нинтендо, синклер, тетрис, спейс-инвайдерс, итп. И всё на полном серьёзе. Как на русском так и на инстрактаблс итп.
    Теперь понимаю, почему один клиент из мед-обласдти уже 3 года гика ищет со знаниями железа, протоколов, сетей, серверов и ИИ ищет и найти не может. Оказывается все демо для спектрума пишут и звуковые карты из резисторов паяют.


    1. Pyhesty
      31.08.2018 13:39
      +2

      уровень мудрости (даже не знаю, как назвать совокупность знаний, опыта, желания учиться и тп) специалиста, который может написать демо для такого железа значительно (намного-намного) выше, чем типичное представление о программисте — как администраторе локальной сети…
      ps: вообще программистов, которые что-то понимаю в железе и могут написать что-то под устаревшую платформу или микропроцессор — немного…


      1. vheinitz
        31.08.2018 14:09
        -1

        При чем тут ассемблер и системное администрирование? В такой манере можно аргументировать «Лучше уж ассемблер чем бухать»

        Я еще застал последние Ассембли-партис. Такого «добра» столько написано, что уже не переплюнуть. Там ни чего нового нет. Мигать спрайтами и проигрывать мод-файлы — это было актуально в 80х-90х. До мп3 и Куда.
        Ассемблер был актуален, когда на рынке было процессоров на пальцах перечесть а не тысячи как сейчас. Не успееш на ассемблере что-то написать, как он уже устарел.
        Полезных заданий на С и сейчас хватает. Возьми какой-либо протокол или алгоритм разгони его до скорости света. Или сделай прибор на контроллере, который гарантированно 10 лет на одной батарейке работает (чем сейчас и занимаюсь:) ).


        1. IvUyr
          31.08.2018 20:06

          Вы таки немного ошибаетесь, это сейчас процессоров мало — iNTEL, AMD (хотя их двоих можно в один свести, как бы оба x86_64), ARM, MIPS, AVR, pic да stm8.
          А раньше были iNTEL, AMD, Zilog, Motorola (68k, 68010, 68020,… 68050), mos, st, ti, DEC PDP, cyrix, arm… Это только те, кого я за пару минут вспомнил.


          1. Pyhesty
            31.08.2018 23:51

            вы забыли миландр, элвис, эльбрус (байкал?)… ;)


            1. Oxyd
              01.09.2018 02:26

              PowerPC и собсно сам Power наше всё!


            1. IvUyr
              01.09.2018 20:35

              "Наши" разработки я намеренно не указал ввиду трудности получения их обычными покупателями (Эльбрус, Байкал) и тем, что внутрях, в общем-то, те же arm да mips..


    1. u-235
      31.08.2018 13:58

      уже 3 года гика ищет со знаниями железа, протоколов, сетей, серверов и ИИ ищет и найти не может


    1. edbuwg
      31.08.2018 14:05

      ЗП достойную просто не предлагают — вот и весь секрет многолетних «поисков»


      1. vheinitz
        31.08.2018 14:31

        Да нет, всё нормально с ЗП. Фирма просото на отшибе. Стоит в поле за три девять земель. Область деятельности мед. диагностика. Там по определению много платят.
        Но фирма маленькая, а в округе фарма-гиганты. Постоянно к себе персонал сманивают. С ними не поконкурируеш.

        Все приходившие информатики совершенно не в курсе что такое предметная область. Боятся почитать что-то про клетки, вирусы; боятся железа (не платин с ЦПУ а реального, с моторами, сенсорами, итп) или просто неопытные.
        Все инженеры в софте мало разбираются. А нужна утка — которая всего понимножку может плавать, летать, ходить.

        Один приходил из Гейделбергского университета, работал там в проекте по распознаванию рака по снимкам легких. Пытал я его, пытал. Спросил, назови одну из важных фич в векторе обучения вашей системы — говорит «возраст». Короче, скажи мне твой возраст и я с точностью 70% определю у тебя рак и без рентгена.


    1. Error1024 Автор
      31.08.2018 15:17

      Оказывается все демо для спектрума пишут и звуковые карты из резисторов паяют.

      Кто «все»? — большенство разработчиков не слышали или слышать не хотят о демосцене.


  1. dimitry78
    31.08.2018 23:37

    Насчет демки круто и посильно! в разумное время достойное творение. сам не железячник, а познакомился с компами на msx yamaha


    1. DolphinSoft
      01.09.2018 18:00
      +2

      Тоже отнастольгировал тут недавно, достав запылившегося ученика. Решил отдать ему дань уважения, апнуть до 4Мб оперативы и поменять VDP с прошивкой, превратив в полноценный MSX2+.
      А тем временем, тоже наваял пару зрелищь как раз под него:
      1.


      1. DolphinSoft
        01.09.2018 18:11

        К слову, размер первого кода — чистые 256 байт (в ассемблере), второго — чуть больше.


  1. AntonSazonov
    01.09.2018 10:06

    А зачем нужно хранить массивы fake_points1 и normal_points? Это же просто степень двойки. Не прощще их генерировать?


    1. Error1024 Автор
      01.09.2018 12:42

      Из-за применения пакера дешевле оказалось хранить, чем генерировать.


      1. AntonSazonov
        01.09.2018 13:28

        А хранить один массив, но обращаться к нему по-разному (arr[i] и arr[7-i] соответственно) не пробовали? Возможно так можно было бы сэкономить ещё пару байт?


        1. Error1024 Автор
          01.09.2018 14:43
          +1

          Это только увеличит размер, тут вся фишка в том что процедура рисования пикселя одна на всю интро, без частных случаев.