Это еще одна статья про демосцену, сайзкодинг, ассемблер, MS-DOS и ретрокодинг. То есть, о том, как ночами напролет добровольно и бесплатно писать бесполезный и очень трудоемкий код и поседеть в 30 лет. Но вдруг вам захочется?
Вступление
Привет, меня зовут bitl и я из тех, кто в детстве не наигрался с кодингом под DOS, и занимаюсь этим в 2020-х, просто ради удовольствия. Изучение "дедовских" технологий, переизобретение старых и придумывание новых методов, алгоритмов и трюков, связанных с ограничениями старого "железа", в общем, тем, что сегодня называется "ретрокодинг". Так сложилось, что я с детства угорел по демосцене, поэтому и сейчас мой интерес в первую очередь связан с этой субкультурой. А так как моим первым компьютером был IBM PC-совместимый ПК (486SX), то MS-DOS - это моя платформа для ностальгирования. Хотя, надо отметить, демосцена не ограничивается ни ретрокодингом, ни ПиСи.
Но сейчас речь пойдет про одно конкретное направление, а именно про "сайзкодинг" (sizecoding). В демосценерской тусовке к этому жанру относят крошечные программки, показывающие какой-нибудь видеоэффект (или несколько), иногда со звуковым сопровождением. В народе это называют "демками" (наряду с большими), но на демосцене это классифицируется (и называется) как "интро" (intro), поэтому далее я так и буду это называть. Под "сайзкодингом" обычно подразумевается создание интры размером не более 4кб, а основными категориями являются 128, 256, 512, 1024, 4096 байт. Хотя для настоящих наркоманов ценителей есть также категории 8, 16, 32, 64 байт (например, на ежегодном онлайн-конкурсе Lovebyte: https://lovebyte.party/#competitions).
И так как я специализируюсь на платформе MS-DOS, то и говорить мы будет сугубо про кодинг под DOS для PC. Хотя сайзкодинг существует и популярен и на ретро-платформах, вроде ZX Spectrum, Commodore-64, Amiga, Atari, БК 0010 и даже на игровых приставках. Ну и Linux, Windows и JavaScript - тоже не исключение. Отдельно можно отметить fantasy-консоли (TIC-80, PICO-8, и т.п.), но это другая песня.
Наиболее каноничной и популярной стала категория "256 байт", этакая золотая середина. И что характерно, всё это набрало обороты именно тогда, когда DOS давно перестал быть актуальной ОС для практического применения. Рост популярности пришелся на конец 90-х, тогда же появились и соответствующие конкурсы (compo) на демо-вечеринках (Demoparty), а также онлайн-конкурсы. С тех пор прошло четверть века, и уж и Windows давно не позволяет запускать DOS-программы, но ничего не закончилось, каждый год сайзкодеры дарят миру еще несколько шедевров, в чем вы сейчас сможете убедиться.
Примеры 256-байтных интро
Перед тем, как перейти к технической части, давайте полюбуемся на избранные образцы данного жанра, чтобы стало ясно, о чем вообще речь:
Да, это все самодостаточные программы для DOS размером 256 байт. Нет, никаких библиотек они не используют, только DOS, центральный процессор x86, сопроцессор x87, VGA-совместимая видеокарта. Но не пугайтесь, это все же выборка из топовых релизов 20-летия. Далеко не все работы в этой номинации такие крутые :) Среднестатистическая интро все же несколько попроще, что не мешает им быть симпатичными, интересными и побеждать на конкурсах (которых проводится не мало и по всему миру, и это не только онлайн-мероприятия, а настоящие компьютерные фестивали). Поэтому если вы вдруг решите попробовать свои силы на этом поле, и решите выставить работу на конкурс, то не стоит волноваться, вряд ли вам прийдется соревноваться с чем-то вроде представленных выше образчиков. Да и в целом, на демосцене не хейтят новичков (по крайней мере последние лет 15).
Зачем вообще это надо?
Теперь, когда мы в общих чертах разобрались - о чем эта статья, перед тем как перейти к ассемблеру, хотелось бы обозначить еще несколько моментов. Во-первых: создавать такие штуки не так уж и сложно. Вам не надо быть каким-то крутым кодером, программистом, хакером, математиком. Некоторые сайзкодеры вообще не являются профессиональными программистами (например, я). Во-вторых: это просто развлечение, сайзкодинг вряд ли даст вам навыки, применимые в нормальном программировании, хотя это и неплохая разминка для
На кого рассчитана эта статья?
Данная статья задумывалась как попытка поделится опытом новичка в области сайзкодинга по свежему опыту, так сказать, пока не забыл. Забавно, но первую 256-байт интро я написал в 2022 году, хотя я активный участник демосцены с конца 90-х. Ранее я писал демо и 64кб (килобайт!) интро под DOS и Windows, писал трекерную музыку, делал сценерский электронный журнал (diskmag), но вот опыта написания чего-то на чистом ассемблере не имел. Хотя, конечно, я иногда писал всякие рутины (процедуры) на встроенном ассемблере Turbo Pascal, Delphi, Visual C++, но там мне не приходилось озадачиваться такими вещами, как выделение памяти, инициализация переменных, и т.п. Это все было на стороне высокоуровнего языка. Так что я понятия не имел - как это делать на чистом Ассемблере. Это казалось каким-то геморроем. А учебники по ассемблеру на меня навевали тоску своей сухостью еще со школьных времен :)
Но я все же имел некоторые навыки в программировании графики, общее понимание - как организована память в реальном режиме DOS, что такое регистры, что такое стек и т.п. Для того чтобы попробовать свои силы в сайзкодинге и "чисто-ассемблерном" программировании, мне не хватало поджопника некоторой базы, эдакого понятного фреймворка, с которого я бы мог начать. Так что, продолжая эту статью, я буду надеяться, что вы из таких же лентяев :)
Я не буду здесь пытаться научить вас придумывать видеоэффекты, объяснять, как работает тот или иной эффект или давать вводный курс булевой алгебры (может быть, если такие просьбы поступят, я сделаю это в следующей статье).
Здесь же я объясню и покажу - с чего вообще начать, когда у вас в руках только ассемблер для MS-DOS, приведу примеры базовой организации кода для крошечных интро, как работать с памятью, и вообще "чо как". Но, естественно, все применительно к интро. Писать так, например, игры, или какие-то прикладные программы - я не советую :)
Возможно, вы имели опыт программирования на ассемблере для ZX Spectrum, и давно хотели попробовать свои силы на PC-платформе? Тогда вы также пришли по адресу.
Начинаем писать свою первую интро
В конце 2021 года мне в "телегу" написал Vinny, организатор DiHalt (ежегодного демопати в Нижнем Новгороде) и спросил, не хочу ли я чего-нибудь прислать (надо отдать ему должное, он ежегодно и неустанно пинает всех сценеров, хотя это и не всегда приносит результаты). На тот момент я уже давно ни черта не делал для демосцены, но, по счастью, как раз занимался раскопками на своих старых винтах, где у меня остались архивы еще с DOS-времён. Я установил DosBox и принялся ковыряться в старье. Пропустим тот фрагмент, где я таки не найдя ничего, что не стыдно было бы релизить на пати, накорябал с нуля на Паскале алгоритм простенького олдскульного эффекта ("интерференция"), решил - а не попробовать ли это переписать на чистый ассемблер, ведь алгоритм достаточно простой и должен уместиться в 256 байт (в теории). Спойлер: все получилось, и хотя первое место интра не заняла, но зато я наконец нашел себе увлекательное занятие на годы вперед. Однако здесь мы её разбирать не будем, по крайней мере в этот раз.
Я использовал что было под рукой, старый Turbo Assembler 2.02 (1990 г.), он уже поддерживает инструкции 80486, а большего мне и не было надо (и до сих пор не пригодилось). Вы можете использовать и более современные ассемблеры (NASM, YASM), на самом деле без разницы, но те примеры кода, которые я буду приводить, компилируются TASM'ом (для других нужно местами немного подправлять синтаксис).
Естественно вам также понадобится собственно DOSBOX (если вы не собираетесь программировать из под реального DOS, что плохая идея, так как в процессе разработки вы вероятно будете "вешать" свой комп по сто раз в час, а перезапустить DosBox все же быстрее, чем ребутиться. Вместо официального DosBox 0.74-3 (который не обновлялся с 2019-го) можно использовать форк под именем DosBox-X, который более точно эмулирует DOS-компьютер и имеет графический интерфейс для настройки. Главное на что стоит обратить внимание это "циклы" (cycles), официальный DosBox по умолчанию имеет настройку "cycles=auto", которая работает не пойми как, в итоге вы получаете скорость 286-го ПК.
Можно поставить статическое значение cycles=60000, это примерно соответствует Pentium 100 MHz. Далее смотрите по обстоятельствам. Слишком большое значение будет сильно загружать ваш реальный процессор.
Вам скорее всего также понадобится файловый менеджер. Я использую DOS Navigator, в том числе и его встроенный текстовый редактор для написания кода. Я также пользуюсь HEX-редактором Qview, который имеет дизассемблер, чтобы анализировать скомпилированный код (оценивать размер инструкций и данных, медитировать, биться головой об стол и все такое).
Итак, допустим, вы обдумали свой видеоэффект (лучше, если вы его уже запрограммировали на языке высокого уровня, оптимизировали размер кода как только сумели, и даже переписали основные части на асм, используя встроенный ассемблер, и отладили). Для создания миниатюрных программ используется COM-формат (а не EXE), он содержит только ваш код (и данные, которые вы сами пропишите), ничего лишнего. Фактически это ваш ASM-код, транслированный в OP-коды процессора. Но все же, в исходнике вам надо прописать некоторые директивы для компилятора, соблюдая синтаксис и порядок. К вашему счастью, я с этим уже разобрался и рассказываю.
Пропуская некоторые итерации, показываю как выглядит код программы для TASM 2.02, которая после запуска инициализирует графический режим 13h (стандартный VGA 320х200, 256 цветов), входит в основной цикл, с условием выхода из него по ESC, восстанавливает текстовый режим (03h) и возвращает управление DOS-у:
comment + .
"My first intro"
comment end! +
.model tiny ;использовать модель памяти "tiny" (всегда для com-программы)
.code
.486
org 0100h ;указываем компилятору смещение для начала нашего кода
;первые 256 байт в сегменте DOS использует под свои цели
start:
mov ax, 13h ;записываем в регистр AX значение 0013h (AH=0, AL=13h)
int 10h ;вызываем функцию BIOS "10h" которая установит видеорежим
; MAIN LOOP
@mainloop:
in al, 60h ;считываем значение из порта клавиатуры в регистр al
dec al ;уменьшаем значение в регистре al на 1
jnz @mainloop ;возвращаемся на позицию "@mainloop" если результат не ноль
; EXIT
mov ax, 3h ;записываем в регистр AX значение 0003h (AH=0, AL=3h)
int 10h ;вызываем функцию BIOS 10h которая установит текстовый режим
int 20h ;вызывем функцию DOS которая возвращает управление системе
end start
Чтобы скомпилировать это в исполнительный COM-файл, надо выполнить две команды:tasm /m4 intro.asm
tlink /t intro.obj
Первая создает obj-файл, опция /m4 означает, что надо сделать 4 прохода. Это нужно, чтобы компилятор не вставлял ненужные NOP-инструкции. Вообще, обычно достаточно и 2-х проходов, но я на всякий случай ставлю 4, чтоб уж наверняка :) Вторая команда создаст из obj-файла нужный нам COM. Опция /t говорит линкеру, что нам нужен именно COM (tiny).Чтобы каждый раз не писать эти команды, можно просто сделать bat-файл и запускать его. Ну или придумайте сами некую автоматизацию. Возможно, есть какие-то удобные IDE для DOS-ассемблера, но мне лень было искать.
Чтобы долго не топтаться на месте, добавляя по капле функционала, давайте сразу напишем какую-никакую интру с простеньким эффектом, но который охватит сразу несколько задач, которые вам скорее всего придется решать.
Сделаем заполнение экрана пикселями с рандомной позицией с фильтром размытия в цветах оттенков серого (grayscale). Схема рендера одного кадра такая:
1. Рисуем 1000 пикселей белого цвета в случайных позициях экрана
2. Проходим алгоритмом размытия весь экран (усреднение по 4 соседним пикселям)
Делаем это в цикле. В теории получим этакий размытый TV-шум.
Нам понадобится:
1. Установить наш любимый режим VGA 320x200
2. Установить grayscale-палитру (VGA-режим является индексным, где мы имеем палитру из 256 цветов (с индексами 0..255), для каждого мы можем предустановить цвет RGB-компонентами, каждая в диапазоне 0..63. Но я надеюсь вы в курсе.
3. Выделить память для видео-буфера. Зачем нам буфер? В данном случае он нужен, потому что мы собираемся "размывать" (блюрить) содержимое кадра, что подразумевает чтение значений пикселей. Читать из видео-памяти (сегмента A000h) очень плохая идея. Это немедленно вызовет катастрофические тормоза. Не будем сейчас останавливаться на вопросе - почему, просто запомните, что мы ничего не читаем из видеопамяти, только записываем. И да, DosBox не воспроизведет проблему, ему все равно, но на реальном "железе" попытка "блюрить" прямо в видеопамяти обернется слайд-шоу. А так как мы порядочные демокодеры и пишем код который будет хорошо работать не только в DosBox, но и на настоящей DOS-машине, то будем делать все через буфер, хотя это и потребует дополнительных накладных расходов.
4. Далее. Нам потребуется генератор псевдо-случайных чисел, выдающий нам случайное число от 0 до 65535. В режиме 320х200 смещение в сегменте для пикселя лежит в диапазоне 0..63999, но мы будем рисовать и блюрить во все 64кб, то есть в 0..65535 байт, чтобы не усложнять. Для сайзкодинга это обычная практика.
5. Простенькая рутина усреднения по 4 соседним пикселям, вида:
for y=0 to 199 do
for x=0 to 319 do
buf[x,y] = (buf[x+1,y]+buf[x-1,y]+buf[x,y+1]+buf[x,y-1]) / 4;
6. Также нам надо будет копировать содержимое видеобуфера в видеопамять.
7. И возвращаемся в пункт 4, пока не нажат ESC.
Будем разбирать сразу в коде:
comment + .
"My first intro"
comment end! +
.model tiny
.code
.486
org 0100h
start:
mov ax, 13h ; устанавливаем VGA-режим
int 10h
;---------------------------------------------------------------------
mov ax, ds ; формируем адрес сегмента для экранного буфера
add ax, 1000h ; (разберем этот момент чуть позже)
mov ds, ax ; адрес сегмента буфера будем хранить в регистре DS
;---------------------------------------------------------------------
mov dx, 0a000h ; присваиваем регистру ES адрес сегмента видеопамяти
mov es, dx ; (присвоить ES константное значение напрямую нельзя)
;---------------------------------------------------------------------
mov bl, 63 ; устанавливаем grayscale-палитру для цветов 0..63
@pal: ; используем для этого функцию BIOS "1010h"
mov dh, bl ; dh = красный компонент
mov ch, bl ; ch = зеленый
mov cl, bl ; cl = синий
mov ax, 1010h
int 10h
dec bl ; bl - индекс цвета
jnz @pal
;---------------------------------------------------------------------
; ПОЕХАЛИ!
@mainloop: ; ГЛАВНЫЙ ЦИКЛ
;---------------------------------------------------------------------
mov cx, 1000 ; нарисуем в буфер точек с рандомными позициями
@dots:
in ax, 40h ; формируем псевдо-случайное 16-битное число
xadd bx, ax ; на основе значений системного таймера
xor ah, al ; (разберем этот момент позже)
mov di, ax ; это число послужит смещением
mov byte ptr ds:[di], 64 ; копируем байт со значением "64" в буфер
loop @dots ; делаем это 1000 раз
;---------------------------------------------------------------------
xor si, si ; Заблюрим буфер
xor cx, cx ; обнуляем CX
@blur: ; цикл в этом случае повторится 65536 раз
mov al, ds:[si-1] ; то есть мы пройдем попиксельно весь сегмент 64кб
add al, ds:[si+1]
add al, ds:[si-320]
add al, ds:[si+320] ; в al получили сумму 4-х соседних пикселей
shr al, 2 ; (2 битовых сдвига вправо - равносильно делению на 4)
mov ds:[si], al
inc si
loop @blur
;---------------------------------------------------------------------
xor di, di ; ок, давайте быстро скопиуем буфер в видеопамять
xor si, si ; напоминаю, буфер у нас DS, видеопамять ES
mov cx, 16000 ; Будем копировать сразу по 4 байта, DWORD'ами
rep movsd ; 320*200/4 = 16000
;---------------------------------------------------------------------
in al, 60h ; повторяем главный цикл пока не нажат ESC
dec al
jnz @mainloop
; EXIT
mov ax, 3 ; возвращаемся в текстовый режим
int 10h
int 20h ; выходим в DOS
end start
После компиляции у нас получится COM-файл размером ровно 100 байт (хех, я не подстраивался, так совпало), который показывает вот такой эффект:
Невесть что, но ведь у нас еще есть целых 156 байт чтобы добавить 3D с освещением, тенями и музыку! Но не в этот раз. Да и приведенный выше код нуждается в оптимизации. Мы попробуем его уменьшить, но сначала давайте разберем несколько фрагментов кода.
1. Мы лихо откуда-то взяли память для буфера. Хотя казалось бы, мы ничего не запрашивали у системы, а просто добавили к значению в сегменте DS число 1000h (4096 в десятичном виде) и решили что там будет наш буфер размером в 64 кб (справка: на старте COM-программы регистр DS, (как и ES, CS, SS, DX) содержит адрес сегмента, в котором находится наша программа).
Да, так можно. Память выше нашего программного сегмента (куда загружена наша COM-программа и где по умолчанию находится и стек) можно относительно безопасно использовать для любых целей нашего ненормального программирования.
Почему я добавил 1000h к адресу сегмента? 1000h = 4096, а адрес сегмента исчисляется в параграфах равных 16 байтам. В общем, почитайте Вики :) 4096*16 = 65536 байт. То есть ровно +64 кб. Таким образом мы используем для буфера память ровно после сегмента выделенного для нашей программы. Хотя такой точности и не требуется, главное не пересечься.
Мы могли бы сделать все культурно и попросить у DOS-a нужное количество памяти и он бы выдал нам адрес свободной области запрошенного размера, но это потребует лишние байты кода, а мы тут собрались не чтобы байтами раскидываться. Поэтому остается надеяться, что мы не влезем в область, которую использует какая-нибудь резидентная программа. Но в конце концов, наш DOS-компьютер не управляет атомной станцией.
2. Далее. Что за фокусы с генерацией случайных чисел? Обычно, более менее порядочная функция random'a выглядит чуть сложнее трех строчек. Но мы не можем себе позволить такой роскоши. Так что лично я пришел к такому решению:
in ax, 40h ; читаем в AX из порта ввода-вывода 40h (таймер Intel 8253/8254)
xadd bx, ax ; обмениваем содержимое регистров AX<->BX,
; затем в BX кладем их сумму.
; В роли BX может быть ячейка памяти или другой свободный регистр.
xor ah, al ; ксорим верхние 8 бит на нижние 8 бит в регистре AX
; этот XOR не обязателен, но с ним рандом более качественный
Оптимизация размера
Надеюсь, остальной код вам более менее понятен. Тогда попробую продемонстрировать суть "сайзкодинга". Да, то что выше - это еще не он :) Поехали выкраивать байты!
start:
mov al, 13h ; заменим AX на AL, потому что на старте программы AL=0,AH=0
int 10h ; и нам достаточно присвоить 8-битное значение.
Это минус 1 байт
Стартовые значения регистров почти всегда эксплуатируются для оптимизации размера!
Стартовое значение регистра DX всегда равно значению регистров DS,ES,CS,SS
и обозначает адрес сегмента программы.
Так что мы сделаем так:
add dx, 1000h
mov ds, dx
еще минус 1 байт
Но можно сделать еще лучше:
add dh, 10h
mov ds, dx
Смысл не поменялся, но мы выгадали еще 1 байт
Нам нужно записать в сегментный регистр ES значение "0A000h".
напрямую mov es, 0a000h сделать нельзя, поэтому мы делали это
через регистр общего назначения DX
mov dx, 0a000h
mov es, dx
Однако через стек будет на 1 байт короче:
push 0a000h
pop es
Далее к инициализации палитры:
; на данном этапе мы еще не трогали регистр BX, а на старте программы
; он, как и AX, равен нулю.
mov bl, 63 ; так что мы можем не волноваться, здесь BH=0, BL=63
@pal:
mov dh, bl
mov ch, bl
mov cl, bl
mov ax, 1010h
int 10h
dec bx ; поэтому здесь мы можем смело заменить "dec BL" на "dec BX"
jnz @pal ; а все OP-коды dec/inc с 16-битными регистрами весят 1 байт
; тогда как с 8-битными (половинками регистров) - 2 байта
Минус еще 1 байт!
Идем в главный цикл, к фрагменту рисующему рандомные точки в буфер:
mov cx, 1000
@dots:
in ax, 40h
xadd bx, ax
xor ah, al
xchg di, ax ; заменили "mov" на "xchg". "Xchg" регистра AX с любым другим
; весит 1 байт, тогда как "mov" 2 байта.
; А по логике алгоритма данная замена ничего не портит
mov byte ptr ds:[di], 64
loop @dots
Сэкономили еще 1 байт.
К фрагменту выполняющему "блюр":
xor si, si
xor cx, cx <-- это обнуление CX не нужно, так как после предыдущего
цикла CX и так всегда обнулён. Удаляем эту строку
и выигрываем целых 2 байта :)
@blur:
mov al, ds:[si-1]
add al, ds:[si+1]
add al, ds:[si-320]
add al, ds:[si+320]
shr al, 2
mov ds:[si], al
inc si
loop @blur
Часть с копированием буфера в видеопамять:
xor di, di
xor si, si ; <-- это можно убрать, так как после "блюра" в нашей ситуации
mov cx, 16000 ; регистр SI всегда равен 0. Но здесь надо быть внимательным
rep movsd ; нельзя допускать ситуацию когда по смещению 65535
; происходит запись или чтение WORD, или DWORD! Будет взрыв!
Минус 2 байта
И на коде выхода в DOS мы срежем еще байтик:
mov ax, 3 ; выход в текстовый режим на самом деле не обязателен
int 10h ; никакие правила конкурсов сейчас этого не требуют,
; но я предпочитаю им жертвовать в последнюю очередь
ret ; а вот вместо вызова dos-функции "int 20h" используем "RET"
; это сработает (для COM-программы), если на момент выполнения
; этой инструкции у вас в вершине стека лежит 0000h
И того, было 100 байт, стало 89. Так и живем.
Да, конечно, финальную глубокую оптимизацию размера следует делать на последнем этапе, когда вы уже добились визуального результата, который вам нравится, а размер COM-файла превышает лимит на 10-30 байт. Если же у вас перебор на сотню байт, то скорее всего нужно что-то переосмыслить глобально. Но мой опыт говорит о том, что нет ничего невозможного, главное не сдаваться. Зато когда вас осенит и вы вдруг уменьшите свою интру с 300 байт до желанных 256-ти, это будет такой праздник, что вам сразу захочется открыть шампанского (я обычно открываю бутылочку сухого красного).
Возвращаясь к выше написанному коду... На самом деле, для порядка нам следует добавить в главный цикл какой-то ограничитель скорости. Например, ожидание обратного хода вертикальной развертки (WaitVerticalRetrace). Для этого нужно перед кодом копирования буфера в видеопамять добавить следующий код:
mov dx, 3DAh ; Wait for vertical retrace
@w1:
in al, dx
test al, 8
jnz @w1
@w2:
in al, dx
test al, 8
jz @w2
Увы, это добавляет целых 13 байт. Но эту штуку можно урезать, удалив строки со 2-й по 5-ю. То есть оставив только w2-проверку. Функцию ограничения скорости рендера до 70 fps оставшийся код все равно будет выполнять исправно. Разбирать этот код мы тут не будем, просто примите за данность :)
Вот, теперь порядок.
Подведем итоги
Думаю, на этом стоит прерваться. На самом деле я хотел написать лаконичную и короткую статью, где изложить основные необходимые сведения в помощь начинающим сайзкодерам, а также тем, кто имеет опыт кодирования на 8-битных платформах, но хотел бы попробовать свои силы на платформе PC (DOS). Но оказалось, что я графоман многие моменты требуют более тщательного разбора. А может и нет. Напишите об этом в комментариях. В конце концов, смысл сайзкодинга в том, чтобы самостоятельно доходить до ручки ответов, совершать открытия, даже если это "велосипед", в этом и заключается основная радость демокодинга. Ну, кроме той, когда вашу интру показали на какой-нибудь пати, например, в Сиднее, Питтсбурге, или Питере, и вы выиграли маечку.
Но, если вдруг данная статья зайдёт, и будет какой-то фидбек, то почему бы нет, продолжим. А теперь полезные ссылки:
Полезные ссылки
Статьи на Хабре на схожую тему:
Ультра-маленькие демки под DOS
Как демо Memories умещается в 256 байт
Подробный разбор 64b intro: radar
Сайты и сообщества сайзкодеров:
http://www.sizecoding.org
https://discord.gg/pZE5rAQrHx
https://lovebyte.party/
https://nanogems.demozoo.org/
Некоторая документация по x86:
80x86 Integer Instruction Set (8088 - Pentium) (содержит инфу о тактах на инструкцию)
x86 Instruction Set Reference
Мои 256-512 байт интры (и другие):
https://demozoo.org/groups/10118/
или https://www.pouet.net/groups.php?which=1889&order=release
Демосценерские ресурсы (международные):
https://www.pouet.net/
https://www.demoparty.net/
https://demozoo.org/
Демосцена в России:
https://retroscene.org/
https://www.demoscene.ru/
https://chaosconstructions.ru/
http://www.dihalt.org.ru/
That's All, Folks!
Автор: BiTL