Из газеты Born Dead #0A, Самара, 03.07.1999 ================================================================ CODING ================================================================ (c) ALK/XTM КАК КОДИТЬ ОПТИМАЛЬНО. - Любую программу можно соптимизировать до двух байт без потери её функциональности. (Из устных высказываний М.М.А) - Ох, Василь Иваныч, не нравится мне этот Сенкевич... - Не нравится - не ешь! (Из народного фольклора) Нет у меня желания говорить. И не было. Да и о чём собственно? - Как научиться программировать... Просто ламерство какое-то... Depression rules my mind... Не хочу выглядеть этаким ментором. Просто не хочу. Но что делать, надо Born Dead юбилейный выпустить, Chaos Construction на носу опять-же, вот и распирает меня (вроде бы) поделиться с миром о чудесах кодинга (да уж...кто-бы говорил!). В общем, так. Так уж получилось, на этот раз мы с М.М.А представили на CC99 только лишь 512-байтную интру ABSENT. Казалось-бы, ну что можно написать в этих несчастных байтах? Оказалось, многое. В процессе написания интра подвергалась 16-ти (если не больше) оптимизациям, и некоторые их примеры заслуживают (на мой взгляд) внимания. ---------------------------------------------------------------- Взять, например, синус. Его можно использовать во многих эффектах, таких, как плазма (для интры сойдёт), flying по траекториям Лиссажу (no comments), rotation mapping (типа повороты текстур или спрайтов), ну и конечно же 3D - rendering. Обычно синус-таблицу рассчитывают заранее (на Бейсике), и в демах/интрах эта таблица может "кушать" от 256 (8-ми битная) до 512 (16-ти битная) байтов. И что мы будем иметь в 512-ти байтах? Половину займёт синус, а в другой половине - ну максимум 2 call-ных эффекта. Нет, это не наш метод! Следующая процедура генерирует синус-таблицу. Размер:75 байт = 44 байт кода + 31 байт таблиц. Размер получаемой таблицы - 256 байт. Собственно, в таблице хранятся значения синуса от 0 до 2-х PI с шагом 1/128 PI. Если интерпретировать их как дробные части чисел, то они лежат в пределах от 0 до 255/256, т.е. это классический синус с точностью 1/256. Первые 128 байт таблицы при расчётах следует брать со знаком плюс, последние 128 - со знаком минус. Если мысленно представить эту синусоиду, то оба её полупериода окажутся положительными, и при расчётах нужно следить за знаком. Сразу оговорюсь: синус не рассчитывается, слишком долгое, длинное и грустное это занятие. В данном примере значения синуса распаковываются из готового, так сказать, архива. В таблице RLESIN находятся DELTA RLE-данные, по которым строится 1/4 периода таблицы. Вторая четверть - это "зеркальное" отображение первой, ну а второй полупериод - копия первого. Легко! SINTAB EQU #C000 XOR A LD E,A LD D,SINTAB&H;таблица всегда располагается по ;"ровным" адресам #XX00 LD HL,RLESIN EX AF,AF' ;в A' будет формироваться очередное ;значение синуса, начальное значение=0 LRP1 LD A,(HL) RRA RRA RRA AND #F ;биты 3..6 данных - количество байтов ;в пакете LD B,A LD A,(HL) AND 7 ;младшие 3 бита данных - приращение синуса ;от предыдущего LD C,A ; C=+0..+7 EX AF,AF' PVT LD (DE),A;кладём очередное значение в массив INC E ADD A,C ;приращение значения DJNZ PVT ;к следующему значению в пакете EX AF,AF' INC HL ;следующие RLE-данные BIT 6,E JR Z,LRP1;проверка на конец 1/4 периода - >=64 байт ;после выхода DE=#C040 LD L,E LD H,D EX AF,AF';A=#FF LSI2 LD (DE),A;построение второй четверти периода INC E DEC L LD A,(HL);копированием задом-наперёд JR NZ,LSI2 LD C,E ;DE=#C080 HL=#C000 BC=#0080 LDIR ;копирование первого полупериода во второй RET RLESIN ;DELTA-RLE таблица 1/4 периода синуса DEFB #E,#F,#26,#F,#4E,#D DEFB #16,#D,#E,#15,#E,#2D DEFB #C,#D,#C,#D,#2C,#B DEFB #C,#B,#C,#23,#A,#B DEFB #2A,9,#A,#29,8,9,#18 Раньше эта самая процедура "весила" ~115 байт. Кому не лень - посмотрите в BlAME. (и как такое могло тогда просочиться?) ---------------------------------------------------------------- Конечно, в 512 байтах не развернёшься - можно рассчитывать на атрибутные эффекты... Вот процедура вывода атрибутного ч/б спрайта: кто может короче ? ADRSCR EQU #5800 LD HL,SPRITE LD DE,ADRSCR LG2 LD B,8 LG1 RLC (HL) SBC A,A;A=0/#FF ;если сюда вставить AND #COLOR, ;то будет чёрно-#color-ный спрайт. ;если-же добавить ещё ADD A,#COLOR2, ;то будет совсем 2-х цветный спрайт. LD (DE),A INC E DJNZ LG1 INC HL LD A,E SUB ESPR-SPRITE*8&L; =SUB #E0 JR NZ,LG2 RET SPRITE DEFB #1D,#C7,#78,#FE DEFB #35,#AC,#60,#18 DEFB #35,#AC,#63,#98 DEFB #3D,#C6,#73,#58 DEFB #35,#A3,#63,#58 DEFB #35,#A3,#63,#58 DEFB #35,#CE,#7B,#58 ESPR ---------------------------------------------------------------- То же самое, но только спрайт получается псевдо-цветной: LD HL,SPRITE LD DE,ADRSCR LG2 LD B,8 LG1 RLC (HL) SBC A,A AND E RRA ;RRA - только для исключения FLASH LD (DE),A INC E DJNZ LG1 INC HL LD A,E SUB ESPR-SPRITE*8&L JR NZ,LG2 RET ---------------------------------------------------------------- Оно же. Спрайт плавно "проявляется". LD HL,SPRITE LD DE,ADRSCR LD C,0 EI ;только чтобы не зависло LG3 PUSH HL PUSH DE HALT ;можно и побольше - дело вкуса HALT LG2 LD B,8 LG1 RLC (HL) SBC A,A AND E AND C RRA LD (DE),A INC E DJNZ LG1 INC HL LD A,E SUB ESPR-SPRITE*8&L JR NZ,LG2 POP DE POP HL SLI C ;C=0,1,3,7,#F,#1F,#3F,#7F,#FF ;говорят, недокументированная команда.. :) JR NC,LG3 RET ---------------------------------------------------------------- Ещё для атрибутных эффектов "заливают" экран "шахматным полем", чтобы получить большее количество полутонов: LD C,#AA LD HL,#4000 LP1 LD (HL),C INC L JR NZ,LP1 RRC C INC H LD A,H SUB #58 JR NZ,LP1 RET ---------------------------------------------------------------- Далее я буду изъясняться тезисами. (M.M.A: Апрельские тезисы? :) ---------------------------------------------------------------- Если процедура выполняется один раз - зачем её оформлять как процедуру? ---------------------------------------------------------------- По-моему, тем, кто использует конструкции типа: CALL SUBR1 RET следует 'публично высказывать фи'. ---------------------------------------------------------------- Необходимо 4 раза подряд в двух местах выполнить процедуру SUBR2 Неправильно: Нормально: Правильно: CALL SUBR2;3 CALL SUBR_X;3 CALL SUBR_X;3 CALL SUBR2;3 .... .... CALL SUBR2;3 CALL SUBR_X;3 CALL SUBR_X;3 CALL SUBR2;3 .... .... .... .... .... .... .... .... CALL SUBR2;3 SUBR_X LD B,4 ;2 SUBR_X CALL SUBR_Y;3 CALL SUBR2;3 LLX PUSH BC ;1 SUBR_Y CALL SUBR2 ;3 CALL SUBR2;3 CALL SUBR2 ;3 SUBR2 .... CALL SUBR2;3 POP BC ;1 .... .... DJNZ LLX ;2 RET RET ;1 ;24 ;16 ;12 ---------------------------------------------------------------- Если в предыдущем фрагменте программы в регистрах остаются полезные данные, почему бы ими не воспользоваться? Неправильно: Нормально: Правильно: CALL SUBR_N CALL SUBR_N CALL SUBR_N LD HL,0 ;3 XOR A ;1 LD E,D ;1 LD DE,0 ;3 LD H,A ;1 INC DE ;1 LD L,A ;1 LD H,E ;1 LD E,A ;1 LD L,E ;1 LD D,A ;1 ;6 ;5 ;4 SUBR_N .... LD DE,#FFBF RET Неправильно: Правильно: LD A,E ; LD A,E ; CP #5B ; SUB #5B ; JR NZ,$-10; JR NZ,$-10; XOR A ;1 OUT (C),A ; OUT (C),A ; ;1 ;0 ---------------------------------------------------------------- Одного и того же результата можно добиться разными путями. Неправильно: Правильно: LD B,D LD B,D OUT (C),A OUT (C),A LD B,E LD B,E EX AF,AF';1 OUTI ;2 LD A,(HL);1 OUT (C),A;2 INC HL ;1 EX AF,AF';1 ;6 ;2 Ламерство: Нормально: Правильно: Быстро: LD HL,#4000;3 LD HL,#5AFF;3 LD HL,#5B00;3 XOR A ;1 LD BC,#1B00;3 LD DE,#5AFE;3 XOR A ;1 LD L,A ;1 LD (HL),0 ;2 LD BC,#1B00;3 DEC HL ;1 LD H,A ;1 INC HL ;1 LD (HL),C ;1 LD (HL),A ;1 LD E,A ;1 DEC BC ;1 LDDR ;2 BIT 6,H ;2 LD D,A ;1 LD A,C ;1 JR NZ,$-4 ;2 ADD HL,SP ;1 OR B ;1 EI ;1 JP NZ,$-6 ;3 HALT ;1 LD SP,#5B00;3 .3456 PUSH DE ;3456*1 LD SP,HL ;1 ;15 ;12 ;10 ;3468 Как все: Правильно: CALL SUBRA CALL SUBRA PUSH HL ;1 .... .... CALL SUBRA CALL SUBRA .... PUSH HL ;1 CALL SUBRA .... .... CALL SUBRA .... PUSH HL ;1 .... .... .... POP BC POP BC POP DE POP DE POP HL POP HL .... .... SUBRA .... SUBRA .... LD L,H LD L,H SBC A,A SBC A,A LD H,A LD H,A RET ;1 EX (SP),HL;1 JP (HL) ;1 ;4 ;2 ---------------------------------------------------------------- Ну, всё, что знал - рассказал. Из газеты Born Dead #0B, Самара, 01.08.1999 ================================================================ CODING ================================================================ (c) ALK/XTM КАК КОДИТЬ ОПТИМАЛЬНО - ii Уважаемые читатели! Чтобы вам сделать такого, чтобы вы от меня как бы отстали ? В прошлом номере как бы юбилейного BD, имела место быть неприятная как бы опечатка; процедуру очистки экрана (оказывается) можно как бы сократить ещё на один байт. Было написано: Следует читать: XOR A XOR A LD HL,#5B00 LD HL,#5B00 DEC HL DEC HL LD (HL),A LD (HL),A BIT 6,H OR (HL) JR NZ,$-4 JR Z,$-3 ...То есть это как бы не опечатка, просто кое у кого устаревшие как бы представления о взаимодействии как бы концепций на современном этапе эволюции в демомайкинге, как зеркале отечественной сцены. (MMA: ...тенденций банальной эрудиции!)