Inferno #04
22 июня 2003

For Coderz - Макросы под ассемблер Alasm v4.4x.

    О макросе бедном замолвите слово...

(c) Vitamin/CAIG: 

   Наверное, многие кодеры (по крайней ме-
ре, начинающие)  сетовали на некоторые не-
достатки ассемблера, которые, впрочем, от-
сутствовали  у языков более высокого уров-
ня. Это  я  речь  веду  о конструкциях. Но
ведь  можно если и не превратить ассемблер
в  паскаль  или что-нибудь еще, то сделать
программирование более удобным. Для осуще-
ствления  подобной  затеи  нам понадобится
ассемблер,  поддерживающий макросы. Приве-
дённые  ниже  примеры  написаны  под Alasm 
v4.4x. При особом желании их можно переде- 
лать под любой  другой макроассемблер. Так
вот, начнем с одного, то есть двух простых
макросов, которые  могут  сделать работу с
переменными более удобной, нежели раньше.

     MACRO GET
     IFN ?:1+1      ;проверяем на наличие
     LD :0,(:1)     ;переменной
     ELSE
     DISPLAY "Variable :1 is not found"
     ENDIF
     ENDM 

И второй макрос:

     MACRO PUT
     IFN ?:0+1
     LD (:0),:1
     ELSE
     DISPLAY "Variable :0 is not found"
     ENDIF
     ENDM

А пользоваться ими надо так:

xpos  equ 32768   ;объявляем переменную 
     ...
     get b,xpos  ;считали
     ...
     put xpos,a  ;записали

   Регистры могут быть и парные.
В  качестве  переменных не могут использо-
ваться абсолютные адреса.

   Еще  несколько макросов на данную тему.
Пусть у нас есть какая-то сложная структу-
ра  данных и нам надо поудобнее обратиться
к ее элементам. Пусть адрес структуры хра-
нится в IX.

     MACRO MOV
     IFN ?:1+1
     LD :0,(IX+:1)
     ELSE
     DISPLAY "Field :1 is not defined"
     ENDIF
     ENDM

   Пример использования:

BOX   DB 0 ;x 
     DB 1 ;y
     DB 2 ;width
     DB 3 ;heigth

BOX_X EQU 0 
BOX_Y EQU 1 
BOX_W EQU 2 
BOX_H EQU 3 

     LD IX,BOX
     ...
     MOV A,BOX_X
     ...

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

     MACRO MASK
     IFN (?:0+1)&(?:1+1)
     BIT :0,(IX+:1)
     ELSE 
DISPLAY "Field :0 or field :1 not defined" 
     ENDIF
     ENDM

   Для  примера дополним предыдущий пример
строками:

BOX   ... 
     DB 0 ;flag

     ...

BOX_FLAG EQU 4 
 
BOX_FULL EQU 0 
BOX_TURN EQU 1 
BOX_CLOS EQU 2 

     ...

     MASK BOX_FULL,BOX_FLAG    ;проверяем
     JZ ...          ;если что, переходим

   Аналогично, можно  добавить макросы для
установки и снятия битовых переменных.

   Идем дальше. Каждому знакома ошибка вы-
хода за поле при компиляции команд относи-
тельного перехода. Тогда мы берем и испра-
вляем все jr на jp. А потом, когда все уже
соптимизировано, настроено  и есть возмож-
ность  некоторые  jp заменить опять на jr,
но  пойди  найди их среди кучи себе подоб-
ных - зае...,  пардон,  забодаешься  :)  А
следующий  макрос старается делать оптима-
льный  код, автоматически ставя jr,  когда
это возможно, а в остальных случаях - jp.
  Но  есть одна нехорошая особенность: он 
хорошо  работает только с конкретно задан- 
ными  адресами,  либо  с уже определенными 
метками, имхо особенность аласма с его од- 
нопроходностью. Если что, компилятор выда- 
ст  ошибку и вы поменяете jmp на jp. Риска 
немного,  зато во многих случаях он дейст- 
вительно сэкономит вам пямять. 

     MACRO JMP
     LOCAL         ;локальные метки
     DIFF=:0-$-2   ;разность хода

     IF DIFF&#8000 ;если переход вперед

     IF DIFF&#FF80 ;если укладываемся в
     DB #18,DIFF   ;короткий переход
     ELSE
     JP :0         ;если нет
     ENDIF

     ELSE

     DIFF=-DIFF    ;если переход назад
     IF DIFF&#FF80
     DB #18,-DIFF
     ELSE
     JP :0
     ENDIF

     ENDIF
     ENDL
     ENDM

   Можно  модернизировать  данный макрос и
создать несколько новых с именами jz, jnz, 
jc, jnc,  которые будут оптимизировать ус- 
ловные  переходы, и  макрос loop,  который
будет выбирать между djnz и dec b:jp nz.

   А этот макрос позволяет скопировать об-
ласть памяти.

     MACRO COPY
     LOCAL
     OLDADR=$
     DEST=:0
     ORG :1
     DUP :2
     DB {DEST}
     DEST=DEST+1
     EDUP
     ORG $
     ENDL
     ENDM

   А пользоваться им надо так: 
COPY from,to,length. Если длина пересылае- 
мого блока кратна 2, то можно исправить DB
на  DW  и  DEST=DEST+2. Только учтите, что
данный  макрос  очень  медленно работает -
даже медленней,чем бейсик,да и строк доба-
вляет  при  компиляции  2*length. Он нужен
для копирования данных, которые должна вы-
полнять внешняя по отношению к данной про-
цедура.

   Неплохая коллекция макросов поставляет-
ся  в  комплекте  с аласмом, это и счетчик
билдов, и генератор случайной фигни :)

   Как-то  мне  Steve  отдал свои диски на
спектрум,  причем некоторые ему отдал один
чувак по имени Unwinder, который был в на-
шей группе еще до того, как я в ней появи-
лся. Так вот, на одном диске я нашел игру-
шку "Питон", написанную  целиком на макро-
сах  и макросредствах ассемблера. Запуска-
лась она при компиляции и была адаптирова-
на под Tasm. Попытки перенести ее на Alasm
не  увенчались успехом, к тому же я не ра-
зобраля  в принципе ее работы. Но постара-
юсь  ее  найти  и предоставить на всеобщее
обозрение.

   На этом разрешите откланяться. Если что
еще придумаю - расскажу обязательно!

------------------------------------------ 
Alone Coder: 

  Со  своей  стороны  могу прокомментиро- 
вать, что  питона под ALASM написать труд- 
нее,поскольку придётся пропатчить резидент 
ALASM'а, чтобы  он  включил прерывания при 
ассемблировании. К счастью, он вроде бы не 
использует нестандартных стеков... 

...А J7n/4D, программируя под TASM,изобрёл
совершенно безумный макрос. Интересно, что
на ALASM он тоже работает! 
;MACROS LIBRARY Revision 2.0 
;J7n'n'MiKE/4D 98-2001 
     MACRO COP
     IFN :1 
:0 
     COP :0,:1-1
     ENDIF
     ENDM
   Произвольная  команда копируется произ-
вольное число раз! И это в одну строчку!

   А вот оттуда же, новая вариация на тему
выравнивания кода по границе 256 байт:
     MACRO OFFSET
     IFN .$
     DS #100-.$
     ENDIF
     ENDM

   Вот  мой макрос опроса портов клавиату-
ры. Вместо опроса порта #FEFE просто пишем 
"i 2", можно с параметром, тогда можно вы- 
делить нужную клавишу:
     MACRO i
     LD A,-:0
     IN A,(-2) 
IFN ?i:1-2 
     AND :1 
ENDIF 
     ENDM

   Как вы можете заметить, мои макросы од-
нобуквенные. Это  для экономии места в ис-
ходнике. Для  ещё  большей экономии вызовы
макросов  следует писать от поля метки, то
есть вот так: 
i     2,1 
   Хотел я сделать такой макрос, но не по-
лучилось - русские буквы не понимаются:
    ;MACRO ы
    ;EX DE,HL
    ;ENDM
   Поэтому придётся писать по-старинке:
     DB "ы

   А вот мой вариант JP/JR: 
;Jp/r (UNDEFINED=JR) 
     MACRO j 
IFN ?:0 
     JR :0 
ELSE 
IF :0-$+126/256 
     JR :0 
ELSE 
     JP :0 
ENDIF 
ENDIF 
     ENDM
   Правда, я им не пользуюсь.

   Проверка HL на ноль с возможным перехо-
дом по нулю. Этот макрос не только убавля-
ет исходник,но и позволяет сменить условие
нахождения начала текста в ACEdit. (Макрос
используется  во  всех  проверялках начала
текста в редакторе.)
     MACRO b
     LD A,H
     OR L 
IFN ?b:0-2 
     JR Z,:0 
ENDIF 
     ENDM

   Что  делает  следующий макрос, надеюсь,
объяслять не надо?
     MACRO [
     LD HL,(:0)
     CALL :1
     LD (:0),HL
     ENDM

   Этот  макрос я использовал для хранения
таблицы  скан-кодов  клавиатуры в формате,
описанном в AlCoNews#6:
     MACRO d
     DB :0
     DW :1
     ENDM
   Кстати, его можно зациклить! Только ещё
вопрос, будет ли это выгодно по размеру :)

   Это  просто копирование откуда-то куда-
то (позволяет экономить некоторое количес-
тво места в исходнике):
     MACRO l
     LD HL,(:0)
     LD (:1),HL
     ENDM

   Сравнивалка 16-разрядных чисел.Если да-
ны параметры, то ещё и переход по условию!
     MACRO s
     OR A
     SBC HL,BC
     ADD HL,BC 
IFN ?s:0-2 
     JR :0,:1 
ENDIF 
     ENDM

   Вот это интересный макрос.Такие вот ма-
кросы, совершенно  неожиданные, появляются
при  оптимизации программы. Эту последова-
тельность  команд  я нашёл весьма популяр-
ной, когда  смотрел  распечатку ACE. Вывод
таких  макросов - первый шаг к поиску мест
для сокращения программы по длине.
   Итак: цикл,в котором что-то вызывается,
и что-то (регистр-другой)  инкрементирует-
ся!
     MACRO c 
LOCAL 
cc 
     CALL :0 
IFN ?c:1-2 
     INC :1 
ENDIF 
IFN ?c:2-2 
     INC :2 
ENDIF 
     DJNZ cc 
ENDL 
     ENDM

   На  самом  деле можно было бы не прове-
рять  наличие  параметров (всё-таки ненаг-
лядная  и  недокументированная возможность
ALASM),но тогда при ассемблировании на эк-
ран будут выводиться ошибки,что некрасиво.
К  тому же, лучше точная уверенность в ре-
зультате!






Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Ликбез - полноый дизассемблер ПЗУ (часть 14).
Юмор - Анекдоты.
WANTED - Реклама.

В этот день...   18 ноября