Основы создания макросов в Assembler.
Основы создания макросов в Assembler. — it-black.ru Перейти к содержимомуМакросы — это шаблоны для генерации кода. Один раз создав макрос, можно использовать его во многих местах в коде программы. Макросы делают процесс программирования на ассемблере более приятным и простым, а код программы получается понятнее. Макросы позволяют расширять синтаксис ассемблера и даже добавлять собственные «команды», которых нет в процессоре.
Также Макросы могут использоваться для ускорения разработки программного обеспечения для микроконтроллеров на Assembler. В процессе компиляции Макросы заменяются на последовательности команд микроконтроллера. Подобный подход к программированию позволяет приблизить программирование на Assembler по внешнему виду к языку программирования C.
Синтаксис создания макроса
Для создания макроса используется директива macro.
macro [] { }
После директивы пишется название макроса, а также может быть указан список параметров (операндов). Параметры в списке перечисляются через запятую. Внутри фигурных скобок записывается тело макроса.
Тело макроса — это код, который подставляется в то место, где макрос будет вызван. Создание макроса является по сути лишь его объявлением, в этом месте программы никакого кода сгенерировано не будет. Поэтому объявления макросов обычно размещают в самом начале программы или в отдельном файле. Примеры макросов:
; Простой макрос без параметров, предназначенный для завершения программы macro exit_app { mov ax,4C00h int 21h }
После того, как макрос объявлен, в нужном месте программы достаточно написать exit_app. Туда препроцессор FASM автоматически подставит 2 команды, записанные в теле макроса.
Расширение системы команд
Макросы можно использовать для расширения системы команд. Например, часто в программе приходится обнулять регистры. Создадим специальный макрос для этой цели:
; Макрос - команда обнуления регистра macro clr reg { xor reg,reg }
Теперь обнулять регистры в программе можно так:
clr ax ;AX=0 clr si ;SI=0 clr bl ;BL=0
Директива include
Если нужно написать собственный набор макросов и использовать их в своих программах, то будет удобно поместить макросы в отдельный файл и воспользоваться директивой включения файла include. Синтаксис директивы:
include 'путь/к/файлу'
Препроцессор FASM читает указанный файл и подставляет код из него вместо директивы include. В отдельный файл можно также вынести часто используемые процедуры, отдельные функциональные блоки программы или объявления данных.
Макросы с переменным количеством параметров
Возможно также создавать макросы с переменным количеством параметров. В этом случае имя параметра записывается в квадратных скобках. Для генерации кода макрос вызывается столько раз, сколько параметров ему было передано. Например, можно написать специальные макросы для улучшения команд PUSH и POP:
; Макрос - улучшенная команда push macro push [arg] { push arg } ; Макрос - улучшенная команда pop macro pop [arg] { pop arg }
Несмотря на то, что название макроса совпадает с именем команды, в теле макроса это имя считается именем команды. Данные макросы позволяют помещать в стек и извлекать из стека сразу несколько операндов, что упрощает код программы. Пример использования:
push ax,word[si],5 pop dx,cx,ax
В результате препроцессором будет сгенерирован следующий код:
push ax push word[si] push 5 pop dx pop cx pop ax
- Виктор Черемных
- 6 января, 2018
- No Comments
Группа в VK
Обнаружили опечатку?
Сообщите нам об этом, выделите текст с ошибкой и нажмите Ctrl+Enter, будем очень признательны!
Свежие статьи
Облако меток
Похожие статьи
Команды работы с битами.
Работать с отдельными битами операндов можно, используя логические операции и сдвиги. Также в системе команд x86 существуют специальные команды для работы с битами: это команды
Синтаксис объявления меток.
Метка в ассемблере – это символьное имя, обозначающее ячейку памяти, которая содержит некоторую команду. Метка может содержать следующие символы: Буквы (от A до Z и
Локальные переменные.
Локальные переменные в Assembler используются для хранения промежуточных результатов во время выполнения процедуры. В отличие от глобальных, эти переменные являются временными и создаются при запуске
Передача параметров через стек.
В предыдущих уроках все параметры передавались процедурам через регистры. В этой статье мы рассмотрим другой способ — передачу параметров через стек. Часто этот способ оказывается
Instagram Vk Youtube Telegram OdnoklassnikiПолезно знать
Рубрики
Авторы
Определение блоков __asm как макросов C
Twitter LinkedIn Facebook Адрес электронной почты
- Статья
- Чтение занимает 2 мин
Блок, относящийся только к системам Microsoft
Макросы C предоставляют удобный способ вставки кода сборки в исходный код, но они требуют особой осторожности.
поскольку макрос расширяется в одну логическую строку. Для создания безотказных макросов следуйте правилам ниже.Заключайте блок
__asm
в фигурные скобки.Помещайте ключевое слово
__asm
перед каждой инструкцией по сборке.Используйте комментарии на языке C старого стиля (
/* comment */
) вместо комментариев в стиле сборки (; comment
) или однострочных комментариев С (// comment
).
Чтобы проиллюстрировать вышесказанное, в следующем примере определяется простой макрос.
#define PORTIO __asm \ /* Port output */ \ { \ __asm mov al, 2 \ __asm mov dx, 0xD007 \ __asm out dx, al \ }
На первый взгляд три последние ключевые слова __asm
кажутся излишними. Однако они нужны, поскольку макрос развертывается в одну строку.
__asm /* Port output */ { __asm mov al, 2 __asm mov dx, 0xD007 __asm out dx, al }
Третье и четвертое ключевые слова __asm
требуются в качестве разделителей операторов. В блоках __asm
в качестве разделителей операторов признаются только символ новой строки и ключевое слово __asm
. Поскольку блок, определенный как макрос, является одной логической строкой, необходимо отделить каждую инструкцию с помощью __asm
.
Очень важно использовать фигурные скобки. Если опустить их, компилятор может перепутать операторы С и C++ на одной строке справа от вызова макроса. Без закрывающей фигурной скобки компилятор не может определить, где завершается код сборки и где начинаются операторы C или С++ после блока __asm
в качестве инструкций по сборке.
Комментарии в стиле сборки, начинающиеся точкой с запятой (;), продолжаются до конца строки. Это вызывает проблемы с макросами, поскольку компилятор игнорирует все после комментария вплоть до конца логической строки. То же самое можно сказать об однострочных комментариях C или C++ (// comment
). Во избежание ошибок используйте комментарии на языке C старого стиля (/* comment */
) в блоках __asm
, определенных как макросы.
Блок __asm
, записанный в качестве макроса С, может принимать аргументы. В отличие от обычного макроса C, однако, макрос __asm
не может возвращать значение. Невозможно использовать такие макросы в выражениях С или С++.
Следует с особой тщательностью вызывать макросы этого типа. Например, вызов макроса на языке сборки в функции, объявленной с соглашением __fastcall
, может дать неожиданные результаты. (См. раздел Использование и сохранение регистров во встроенной сборке.)
Завершение блока, относящегося только к системам Майкрософт
Встроенный ассемблер
AVR Tutorials — Ассемблерные макросы
Ассемблерные макросы могут быть мощными инструментами, позволяющими повторно использовать последовательности кода снова и снова. Создание библиотеки макросов для наиболее часто используемых функций позволит вам писать код быстрее и делать меньше ошибок.
В отличие от подпрограмм, в которых микроконтроллер переходит к новому разделу кода, ассемблер просто заменяет макросы кодом, который он представляет во время сборки.
Определение макросов
Макросы определяются размещением кода между директивами ассемблера .macro и .endmacro. Например, макрос myMacro может быть определен как
.macro мой макрос ... ; код макроса .endmacro
Макросы очень полезны для блоков кода, которые необходимо использовать во многих программах, не требующих подпрограммы. Например, вы можете обнаружить, что каждая программа, которую вы пишете, должна иметь инициализированный указатель стека. Макрос для этого можно записать как
.macro setStack ldi r16, НИЗКИЙ (RAMEND) вне SPL, r16 ldi r16,ВЫСОКИЙ(РАМЕНД) выход SPH,r16 .endmacro
После определения макроса его можно использовать, просто поместив имя макроса в код
запуск: setStack ; инициализировать указатель стека . .. ; программный код петля: rjmp петля ; бесконечный цикл
Передача параметров в макросы
Можно писать макросы, которые принимают параметры. При написании кода для такого макроса первый передаваемый параметр представляется как @0, второй — как @1, третий — как @2 и т. д. Например, приведенный выше макрос можно переопределить, чтобы он принимал параметр для использования в качестве адреса указателя стека.
.macro setStack лди r16, НИЗКИЙ(@0) вне SPL, r16 лди r16,ВЫСОКИЙ(@0) выход SPH,r16 .endmacro
Затем этот макрос можно использовать как
start: setStack RAMEND ; инициализировать указатель стека ... ; программный код петля: rjmp петля ; бесконечный цикл
Возможно, вы также захотите добавить в качестве параметра регистр, используемый для установки указателя стека. Это можно сделать как
.macro setStack лди @1,НИЗКИЙ(@0) вне SPL,@1 ldi @1,ВЫСОКИЙ(@0) выход SPH,@1 .endmacro
Когда макрос вызывается с несколькими параметрами, они должны быть разделены запятая .
запуск: setStack RAMEND,r16 ; инициализировать указатель стека ... ; программный код петля: rjmp петля ; бесконечный цикл
Условные директивы и обработка ошибок
Условные директивы можно использовать для повышения гибкости ваших макросов и отлова ошибок. Существует ряд условных директив и выходов, которые вы можете использовать, они показаны в таблице ниже.
Директива | Описание |
---|---|
.еще | еще |
.элиф | иначе если |
.если | если |
.ifdef | , если определено |
.ifndef | , если не определено |
.ошибка | выдает ошибку |
.сообщение | вывести сообщение |
.предупреждение | вывести предупреждение |
Например, вы можете включить проверку того, что переданный параметр находится в допустимом диапазоне.
.macro setStack .if @0>РАМЕНД .error "Значение больше, чем RAMEND, используемое для установки стека" .еще лди @1,НИЗКИЙ(@0) вне SPL,@1 лди @1,НИЗКИЙ(@0) вне SPL,@1 .endif .endmacro
Теперь, если используется значение больше, чем RAMEND устройства, ассемблер выдаст ошибку и выведет сообщение в командной строке, указывающее, в чем была проблема.
Объединение макросов и подпрограмм
Помещая вызовы подпрограмм в определения макросов, мы можем создавать более гибкие и простые в использовании подпрограммы.
Например, подпрограмма delay10ms, которую мы написали ранее, требовала загрузки параметра во входной регистр перед ее вызовом. Мы можем просто сделать эту часть макроса, чтобы подпрограмма задержки могла вызываться в одной строке. Кроме того, мы можем сохранить регистры, которые, как мы знаем, будет изменять подпрограмма, поместив их в стек и восстановив их после завершения.
.макрос задержки толчок r18 толчок r24 толчок р25 ldi r18,@0/10 задержка повторного вызова10 мс поп r25 поп r24 поп r18 . endmacro
Теперь нашей подпрограммой стало намного проще пользоваться.
задержек 500 ; задержка на 500 мс
Обратите внимание, что входной параметр для задержки 10 мс указывает, сколько раз мы задержимся на 10 мс. Например, для задержки на 1 с нам пришлось бы передать параметр 100. Разделив его на 10 в макросе выше, мы абстрагировались от этой детали. Макрос позволяет нам просто вызвать подпрограмму с количеством мс, которое мы хотим отложить.
Если вы будете использовать макрос во многих различных программах, вы можете создать новый файл, чтобы поместить макрос и включить его во все программы, которые в нем нуждаются. Например, в файл delayMacro.inc можно поместить следующее.
;****************************************************** *************** ;* макрос: delayms ;* ;* описание: создает задержку на указанное количество ;* миллисекунды ;* ;* inputs: @0 - количество миллисекунд задержки для ;* ;* регистры изменены: нет ;****************************************************** ************* . макрос задержки толчок r18 толчок r24 толчок р25 ldi r18,@0/10 задержка повторного вызова10 мс поп r25 поп r24 поп r18 .endmacro
Используя это, нашу программу из предыдущего примера можно еще больше упростить.
.include "m328pdef.inc" .include "delayMacro.inc" маска .def = r16 ; регистр маски .def ledR = r17 ; светодиодный регистр .def loopCt = r18 ; количество циклов задержки .equ iVal = 39998 ; значение внутреннего цикла .cseg .org 0x00 ldi r16, НИЗКИЙ (RAMEND) ; инициализировать выход SPL,r16 ; указатель стека ldi r16,ВЫСОКИЙ(РАМЕНД) ; в РАМЕНД выход SPH,r16 ; " клр светодиодR ; очистить светодиодный регистр ldi маска,(1<asm" ; включить подпрограмму задержки
Макросы нельзя вызывать, пока они не определены. Таким образом, вы не должны помещать их определения во включаемый файл, который появляется в конце вашего кода. Вместо этого вам следует создать отдельный включаемый файл для определений макросов и поместить его в начало вашей программы.
<< Предыдущая
Следующая >>
Учебник по ассемблеру 8086 для начинающих (часть 10)
Учебник по ассемблеру 8086 для начинающих (часть 10) Учебник по ассемблеру 8086 для начинающих (часть 10)Макросы
Макросы похожи на процедуры, но не совсем. Макросы выглядят как процедуры, но они существуют только до компиляции вашего кода, после компиляции всех макросов заменены реальными инструкциями. Если вы объявили макрос и никогда его не использовали в вашем коде компилятор просто проигнорирует его. emu8086.inc — хороший пример использования макросов, этот файл содержит несколько макросов, облегчающих вам кодирование.
Определение макроса:имя MACRO [параметры,...] <инструкции> ЭНДМ |
В отличие от процедур, макросы должны быть определены над код, который его использует, например:
MyMacro MACRO p1, p2, p3 ДВИГАТЕЛЬ ТОПОР, ч. 1 МОВ БХ, стр.2 МОВ СХ, стр.3 ЭНДМ ОРГ 100ч МойМакрос 1, 2, 3 MyMacro 4, 5, DX РЕТ |
Приведенный выше код расширяется до:
MOV AX, 00001h
MOV BX, 00002h
MOV CX, 00003h
MOV AX, 00004h
MOV BX, 00005h
MOV CX, DX
Некоторые важные факты о макросах и процедурах :
|
Макросы раскрываются прямо в коде, поэтому если внутри есть метки определение макроса, вы можете получить ошибку «Дублировать объявление» при использовании макроса в течение двух и более раз. Чтобы избежать такой проблемы, используйте директиву LOCAL , за которой следует по именам переменных, меток или имен процедур. Например:
MyMacro2 МАКРО МЕСТНАЯ метка1, метка2 КМП ТОПОР, 2 Этикетка JE1 КМП ТОПОР, 3 Этикетка JE2 метка1: ИНК ТОПОР метка2: ДОБАВИТЬ ТОПОР, 2 ЭНДМ ОРГ 100ч МойМакрос2 МойМакрос2 РЕТ |
Если вы планируете использовать макросы в нескольких программах, рекомендуется разместить все макросы в отдельном файле.