Написание макросов в ассемблере

При освоении языка программирования, Ассемблер, в описании инструментов этого языка, упоминается такой элемент, как - Макрос. Зачем он нужен и какая от него польза? Чтобы реально это понять, вероятно, лучше это показать на конкретном примере, конкретной программы.

Для выполнения замысла данной программы необходимо сформировать три разных интервала времени, вызывая эти подпрограммы периодически в разных местах программы, и для создания разных временных интервалов в них, приходилось, использовать разные константы, но при этом пользоваться тремя подпрограммами одного и того же похожего вида.

В регистровую пару, загружалось число (константа) и производилось вычитание единицы из этого числа до тех пор, пока результат не сравняется с нолём. Вычитание разных констант, при определённой тактовой частоте микроконтроллера предполагало формирование разных интервалов времени.

Для данной программы таймера надо сформировать интервалы времени при тактовой частоте внутреннего RC-генератора 128кГц/8, которая выбрана для проекта реализованного на микроконтроллере AVR ATtiny13.


Интервалы длительностью:
1,125 с. получались при константе = 4500
0,2 с. при константе = 800
15 с. При константе = 60000


Это имело такой вид: три похожих куска, три подпрограммы для формирования разных временных интервалов, но имеющая одно выражение, все они похожи между собой, вот пример:

01.;***************************************************************************************

02. Подпрограммы формирования интервалов времени

03.;***************************************************************************************

04.;----------------------- 1.125 s -------------------------------

05.Delay _1: ; T off "Led" = 1,125 s. время когда светодиод погашен

06. ldi XL,Low (4500) ; загружаем константу в нижний регистр регистровой пары Х

07. ldi XH,high (4500) ) ; загружаем константу в верхний регистр регистровой пары Х

08.del:

09. sbiw XL,1 ; вычитаем 1 из двухбайтного слова загруженного в регистровую пару Х

10. brne del ; если результат не равен нолю,снова переходим к метке ( del)

11. ret ; выход из этой подпрограммы

12.;-------------------------------- 0.2s ------------------------------

13.Delay_2: ; ON "Led" =0,2 s. -формирование времени, когда светодиод горит.

14. ldi XL,Low (800)

15. ldi XH,high (800)

16.mm:

17. sbiw XL,1

18. brne mm

19. ret

20.;-------------------------------------- T = 15 Sek. ------------------------------------------

21.Delay_15: ; формирование отрезка времени длительностью 15сек.

22. ldi XL,Low (60000)

23. ldi XH,high (60000)

24.del_:

25. sbiw XL,1

26. brne del_

27. ret

28.;**************************************************************************

Отличие этих подпрограмм - только константы подставлены разные, почему б не объединить это в одно выражение? И вот тут нам поможет облегчить эту задачу макрос.

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

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

1.;=============================================================.equ PAUSE =60000 ;константе (15 c.) присвоили имя – « PAUSE »

2..equ LED_ON =800 ;константе (0,2c) присвоили имя « LED_ON »

3..equ LED_OFF =4500 ;константе (1,125c.) присвоили имя – «LED_ OFF »

4..def counter =r18 ;Регистру повторения количества раз *delay* имя - « counter »

5.;=============================================================

 

Для того, чтобы все три подпрограммы объединить в одно выражение, надо создать макрос. Дадим ему символическое имя - «delay » (задержка). Так же улучшаем характеристики прежней подпрограммы для формирования больших временных интервалов, мы добавляем ещё коэффициент умножения (на сколько надо умножить полученный временной интервал с занесённой константой времени, чтобы получить ещё большие отрезки времени. Этот коэффициент - число на которое надо умножить временной интервал, полученный нами, с использованием соответствующей константы. Эта величина должна быть в пределах от 1 до 255 (255 -максимальное однобайтное число)
И вот что получилось:

 

01.;=============================================================

02.; macros delay

03.;=============================================================

04..macro delay ; присваиваем имя макросу - « delay »

05. Ldi counter,@1 ; здесь @1- это коэффициент повторения макроса K раз(1-255)

06.K:

07.ldi XL,Low (@0) ;Загрузить младший байт константы времени

08.ldi XH,high(@0) ;Загрузить старший байт константы времени

09.delay_:

10.sbiw XL,1; вычитаем единицу из двухбайтного слова загруженного в регистровую пару Х

11. brne delay_

12. dec counter

13. brne K

14..endm ; конец макроса

15.;=============================================================

 

Важный момент! Макрос надо располагать в самом начале программы.
Компилятор ассемблера проходя с начала до конца, читая нашу программу, усваивает условия оговоренные макросом в начале, точно так же, как и присвоение имён переменных и констант и остальные моменты, которые оговариваются в начале. Если мы расположим кусок подпрограммы макроса в конце программы, то он работать не будет и будет воспринят ассемблером, как ошибка.

Вместо трёх получилось одно универсальное выражение. Сравните визуально, сколько сократилось строк в тексте программы.

Теперь, если нужно сформировать временной интервал, то нужно вызвать этот макрос и выглядит эта запись так:

1.;--------------------------------------------------------------------------------------------------------

2.delay PAUSE, 3

3.;--------------------------------------------------------------------------------------------------------

Где delay - это имя макроса, PAUSE - это имя присвоенное нами константе (15 c.). В макросе таких величин-констант может быть записано в строке через запятую до 10-ти возможных (всё зависит от того, какой макрос мы придумаем).

В нашем примере использованы две такие величины @0 и @1, и в данной записи это имя (PAUSE) в своём положении занимает 0-й разряд. В макросе соответствует обозначению с нулевым номером - @0 и поэтому стоит первым по списку в очереди, 3 - это второе число внесённое в макрос и соответствующее обозначению в нём - @1, которое пишется в строке через запятую после написания первого символического имени соответствующего - @0. 3 - Это коэффициент умножения, выбранный нами, на который надо умножить временной интервал = 15 с. с использованием константы, с присвоенным именем - PAUSE, чтобы получить интервал времени = 45 сек.

В результате мы получаем интервал времени равный 45с (15с. х 3).