Да много за счёт чего, в частности сильно экономит использование
даже метких п/п взамен макросов. Если макрос нечасто используется
(не в каком-нить критическом ко времени выполнения цикле,
многократно), то почти всегда выгоднее заменить его на п/п, пусть
даже и с двумя-тремя асемблерными командами всего. не исключаю, что
компилятор может без оптимизации именно задействовать макросы
(которые тиражируются по всей программе), а с оптимизацией заменять
их на call/ret в итоге - всего пара байт, в простейшем случае, вместо десятка(ов) при каждом использовании макроса.
У меня практически каждый макрос (а я использую их много и часто, для лучшей читабельности кода и исключения ошибок), если он больше 2-3 команд - сделан в виде вызова п/п.
Вот. к примеру (ещё и вложенные макросы :)) правда подготовка и вызов макроса 6 байт - но это сложная функция, универсальная - декремент ячейки с контролем нуля. Сохранение Z сделано "чтоб не думать об этом и не влететь где-нить в прерывании на порчу регистра" (а бывают и большие п/п обработки, но это уже в общем-то "написание своего языка" :)). Излишества привнесены в угоду универсальности :)) можно конечно покороче сделать, для конкретного применния.
- только не пинайте сильно, что так нельзя :) - "да ла-а-адно, - можно" (С) :))
;Декремент ячейки ОЗУ, как таймера (однократный отсчет до "0").
;Параметр - ячейка ОЗУ.
;При достижении ячейкой значения "0", счет приостанавливается.
;Синтаксис: TIMER_onceCountDown SRAM_Address
;!! Результат возвращается в регистре TMP, и может быть проанализирован.
;08/II.19
;
.macro TIMER_onceCountDown
PUSH_Z
LDZ @0
rcall decrement_timerCell
POP_Z
.endmacro
;---
;П/П для макроса "TIMER_onceCountDown"
; адрес ячейки RAM передается в регистре "Z", результат возвращается в
; регистре "TMP" (значение числа в ячейке памяти с указанным адресом).
; Если достигли "0", то "0" и остается в ячейке.
;26/IX.06
decrement_timerCell:
ld TMP,Z
subi TMP,1
brcc store_counted_down_Cell ;Отсчитали ли таймаут? Если НЕТ, то сохраняем
clr TMP ; счетчик, иначе стопорим его значение на "нуле".
store_counted_down_Cell:
st Z,TMP ;Сохраняем TMP, по адресу изменяемого счетчика.
ret
;
если посмотреть ассемблерный код моих программ, то там call на call-е и call-ом погоняет :)) - сплошные вызовы п/п, как минимум процентов 30-40 кода :) - ужас для реверсинжиниринга :))
И вообще интенсивное использование подпрограмм - нашеФсё :) - сильно экономит объём, исключает ошибки, затрудняет "реверс", при достаточной в 99.99% случаев производительности :))
Пример - компактный "шитый код" форт-программ.