Здесь показаны различия между двумя версиями данной страницы.
Предыдущая версия справа и слева Предыдущая версия Следующая версия | Предыдущая версия | ||
msx:assembler_programming_guide-fakhrutdinov_bocharov:03 [2020-05-11 16:14] GreyWolf [3.1.1 Генерация текста несколько раз] |
msx:assembler_programming_guide-fakhrutdinov_bocharov:03 [2020-11-25 09:56] (текущий) GreyWolf |
||
---|---|---|---|
Строка 7: | Строка 7: | ||
До сих пор созданием текстов на языке ассемблера (программированием) занимались мы сами, а ассемблер транслировал их в программы на машинном языке. Однако большинство ассемблеров могут кроме этого по определенным правилам сами генерировать команды на языке ассемблера из команд условной генерации и макрокоманд, написанных программистом. | До сих пор созданием текстов на языке ассемблера (программированием) занимались мы сами, а ассемблер транслировал их в программы на машинном языке. Однако большинство ассемблеров могут кроме этого по определенным правилам сами генерировать команды на языке ассемблера из команд условной генерации и макрокоманд, написанных программистом. | ||
- | Такие ассемблеры называют макроассемблерами. К ним относится и макроассемблер M80. Процесс трансляции макроассемблером может состоять из двух этапов: | + | Такие ассемблеры называют макроассемблерами. К ним относится и макроассемблер [[msx:macro-80_assembler:macro-80_assembler|M80]]. Процесс трансляции макроассемблером может состоять из двух этапов: |
- анализ программы и генерация текста на языке ассемблера; | - анализ программы и генерация текста на языке ассемблера; | ||
- генерация программы в машинных кодах. | - генерация программы в машинных кодах. | ||
Строка 45: | Строка 45: | ||
</code> | </code> | ||
- | После трансляции макроассемблером M80 получим следующий листинг: | + | После трансляции макроассемблером [[msx:macro-80_assembler:macro-80_assembler|M80]] получим следующий листинг: |
<code> | <code> | ||
MSX.M-80 1.00 01-Apr-85 PAGE 1 | MSX.M-80 1.00 01-Apr-85 PAGE 1 | ||
Строка 100: | Строка 100: | ||
</code> | </code> | ||
- | Параметр — это любое допустимое имя языка ассемблера. Ассемблер M80 допускает имена, содержащие знак "$". Их удобно использовать для обозначения параметров. | + | Параметр — это любое допустимое имя языка ассемблера. Ассемблер [[msx:macro-80_assembler:macro-80_assembler|M80]] допускает имена, содержащие знак "$". Их удобно использовать для обозначения параметров. |
Команда IRP генерирует команды, каждый раз заменяя параметр в командах очередным значением из списка, а команда IRPC подставляет вместо параметра очередной символ строки. | Команда IRP генерирует команды, каждый раз заменяя параметр в командах очередным значением из списка, а команда IRPC подставляет вместо параметра очередной символ строки. | ||
Строка 115: | Строка 115: | ||
ENDM | ENDM | ||
END | END | ||
- | <code> | + | </code> |
- | После трансляции M80 получим: | + | После трансляции [[msx:macro-80_assembler:macro-80_assembler|M80]] получим: |
<code> | <code> | ||
MSX.M-80 1.00 01-Apr-85 PAGE 1 | MSX.M-80 1.00 01-Apr-85 PAGE 1 | ||
Строка 132: | Строка 132: | ||
0008' 07 + DB 7 | 0008' 07 + DB 7 | ||
END | END | ||
- | <code> | + | </code> |
Пример использования команды IRPC: | Пример использования команды IRPC: | ||
Строка 153: | Строка 153: | ||
0009' C9 RET | 0009' C9 RET | ||
END | END | ||
- | <code> | + | </code> |
{{anchor:n313}} | {{anchor:n313}} | ||
==== 3.1.3. Условная генерация ==== | ==== 3.1.3. Условная генерация ==== | ||
- | Условная генерация — генерация в зависимости от некоторых условий различающихся или различных последовательностей команд ассемблера. Для условной генерации в системе DUAD и в M80 используются конструкции вида: | + | Условная генерация — генерация в зависимости от некоторых условий различающихся или различных последовательностей команд ассемблера. Для условной генерации в системе [[msx:duad:duad|]] и в [[msx:macro-80_assembler:macro-80_assembler|M80]] используются конструкции вида: |
<code> | <code> | ||
IF условие IF условие | IF условие IF условие | ||
Строка 166: | Строка 166: | ||
ENDIF | ENDIF | ||
</code> | </code> | ||
- | Команды-ассемблера-1 генерируются, если условие истинно, команды-ассемблера-2 генерируются, если условие ложно. | + | ''Команды-ассемблера-1'' генерируются, если условие истинно, ''команды-ассемблера-2'' генерируются, если условие ложно. |
Команды условной генерации применяются обычно, когда одна и та же исходная программа должна быть настраиваемой на различные условия эксплуатации. Изменив несколько строк в начале программы и перетранслировав её, можно получить объектный код, рассчитанный например, на другой тип машины или другую её конфигурацию. | Команды условной генерации применяются обычно, когда одна и та же исходная программа должна быть настраиваемой на различные условия эксплуатации. Изменив несколько строк в начале программы и перетранслировав её, можно получить объектный код, рассчитанный например, на другой тип машины или другую её конфигурацию. | ||
Строка 191: | Строка 191: | ||
RET | RET | ||
END | END | ||
- | <code> | + | </code> |
- | После трансляции ассемблером DUAD получим следующий листинг: | + | После трансляции ассемблером [[msx:duad:duad|]] получим следующий листинг: |
<code> | <code> | ||
Z80-Assembler Page: 1 | Z80-Assembler Page: 1 | ||
Строка 218: | Строка 218: | ||
</code> | </code> | ||
- | Обратите внимание, что код, соответствующий MSX, не генерировался. Ниже приведен пример трансляции ассемблером M80 для других условий. Сгенерировано всего 6 байт. | + | Обратите внимание, что код, соответствующий MSX, не генерировался. Ниже приведен пример трансляции ассемблером [[msx:macro-80_assembler:macro-80_assembler|M80]] для других условий. Сгенерировано всего 6 байт. |
<code> | <code> | ||
MSX.M-80 1.00 01-Apr-85 PAGE 1 | MSX.M-80 1.00 01-Apr-85 PAGE 1 | ||
Строка 245: | Строка 245: | ||
</code> | </code> | ||
- | Для команд условной генерации обычно не допускается вложенность одного оператора IF в другой. Если же вложенность макроассемблером допускается, ELSE отвечает ближайшему IF, не имеющему ELSE. | + | Для команд условной генерации обычно не допускается вложенность одного оператора ''IF'' в другой. Если же вложенность макроассемблером допускается, ''ELSE'' отвечает ближайшему ''IF'', не имеющему ''ELSE''. |
{{anchor:n32}} | {{anchor:n32}} | ||
Строка 254: | Строка 254: | ||
Однако адрес может быть как абсолютным, так и заданным относительно данных, кодов или общей памяти. Относительный адрес задает смещение к абсолютному стартовому адресу. | Однако адрес может быть как абсолютным, так и заданным относительно данных, кодов или общей памяти. Относительный адрес задает смещение к абсолютному стартовому адресу. | ||
- | Тип адресации задается директивами ассемблеру — ASEG, CSEG, DSEG, COMMON. | + | Тип адресации задается директивами ассемблеру — ''ASEG'', ''CSEG'', ''DSEG'', ''COMMON''. |
- | ### Определение абсолютного сегмента | + | ==== Определение абсолютного сегмента ==== |
- | Директива ASEG задает абсолютный режим адресации. При этом генерируются абсолютные коды, жестко привязанные к одному участку памяти. | + | Директива ''ASEG'' задает абсолютный режим адресации. При этом генерируются абсолютные коды, жестко привязанные к одному участку памяти. |
- | После директивы ASEG директива ORG должна использоваться с аргументом 103h или больше, причем она задаёт абсолютный адрес трансляции. | + | После директивы ''ASEG'' директива ''ORG'' должна использоваться с аргументом 103h или больше, причем она задаёт абсолютный адрес трансляции. |
- | ### Определение сегмента относительно кодов | + | ==== Определение сегмента относительно кодов ==== |
Директива CSEG задает режим трансляции относительно кодов. | Директива CSEG задает режим трансляции относительно кодов. | ||
Строка 275: | Строка 275: | ||
Режим CSEG является стандартным режимом работы ассемблера. | Режим CSEG является стандартным режимом работы ассемблера. | ||
- | ### Определение сегмента относительно данных | + | ==== Определение сегмента относительно данных ==== |
- | Для задания этого режима адресации используется директива DSEG. Признаком этого режима трансляции являются двойные кавычки после адреса ("). | + | Для задания этого режима адресации используется директива ''DSEG''. Признаком этого режима трансляции являются двойные кавычки после адреса (%% " %%). |
- | Как и в режиме CSEG, устанавливается то значение счетчика адреса, которое было последним в режиме DSEG, а директива ORG задает относительное смещение адреса. | + | Как и в режиме ''CSEG'', устанавливается то значение счетчика адреса, которое было последним в режиме ''DSEG'', а директива ''ORG'' задает относительное смещение адреса. |
- | Для установки абсолютного адреса в сборщике используется ключ /D. | + | Для установки абсолютного адреса в сборщике используется ключ ''/D''. |
- | ### Определение блока общей области | + | ==== Определение блока общей области ==== |
- | Директива `COMMON /[ имя-блока]/` определяет некоторую общую область данных для всех блоков COMMON, известных редактору связей, и является неисполняемой директивой резервирования памяти. | + | Директива ''COMMON /[ имя-блока]/'' определяет некоторую общую область данных для всех блоков COMMON, известных редактору связей, и является неисполняемой директивой резервирования памяти. |
Признак этого режима трансляции — восклицательный знак (!) после адреса. Как и раньше, директива ORG задает относительный адрес. | Признак этого режима трансляции — восклицательный знак (!) после адреса. Как и раньше, директива ORG задает относительный адрес. | ||
Строка 291: | Строка 291: | ||
Через общие блоки с одним и тем же именем разные подпрограммы могут обмениваться данными и результатами. | Через общие блоки с одним и тем же именем разные подпрограммы могут обмениваться данными и результатами. | ||
- | ### Смещение | + | ==== Смещение ==== |
Иногда требуется временно хранить программу в одном месте для последующего переписывания и выполнения в другом. Для этого используется директива | Иногда требуется временно хранить программу в одном месте для последующего переписывания и выполнения в другом. Для этого используется директива | ||
- | ``` | + | <code> |
.PHASE выражение. | .PHASE выражение. | ||
- | ``` | + | </code> |
Выражение должно иметь абсолютное значение. | Выражение должно иметь абсолютное значение. | ||
- | Директива `.DEPHASE` используется для обозначения конца трансляции такого смещенного блока кодов. | + | Директива ''.DEPHASE'' используется для обозначения конца трансляции такого смещенного блока кодов. |
- | Ниже приводится пример программы, использующей некоторые директивы управления адресами. Эта программа работает посредством обработки прерываний от таймера (60 раз в секунду). Напомним, что по этому прерыванию центральный процесор выполняет подпрограмму обработки прерывания, находящуюся по адресу 0038h. | + | Ниже приводится пример программы, использующей некоторые директивы управления адресами. Эта программа работает посредством обработки прерываний от таймера (60 раз в секунду). Напомним, что по этому прерыванию центральный процессор выполняет подпрограмму обработки прерывания, находящуюся по адресу 0038h. |
- | Как и любая другая подпрограмма обработки прерывания, она начинается с сохранения регистров (путем засылки их в стек), затем вызывается ловушка этого прерывания (0FD9Ah), в которой вначале находится команда возврата (RET). | + | Как и любая другая подпрограмма обработки прерывания, она начинается с сохранения регистров (путем засылки их в стек), затем вызывается ловушка этого прерывания (0FD9Ah), в которой вначале находится команда возврата (''RET''). |
- | При инициализации наша программа перемещает свой код в область, начиная с адреса 4000h (которая интерпретатором языка BASIC не используется) и через ловушку прерывания устанавливает | + | При инициализации наша программа перемещает свой код в область, начиная с адреса 4000h (которая интерпретатором языка [[msx:basic:|]] не используется) и через ловушку прерывания устанавливает |
точку входа. | точку входа. | ||
- | Суть самой программы заключается в том, что она два раза в секунду печатает системное время в правом верхнем углу экрана (SCREEN 0, WIDTH 80). Мы уже сказали, что используемое прерывание происходит 60 раз в секунду (во всей доступной авторам литературе указывается число 50), т.е. каждый тридцатый вызов этого прерывания указывает на то, что прошло 1/2 секунды. | + | Суть самой программы заключается в том, что она два раза в секунду печатает системное время в правом верхнем углу экрана (''SCREEN 0'', ''WIDTH 80''). Мы уже сказали, что используемое прерывание происходит 60 раз в секунду (во всей доступной авторам литературе указывается число 50), т.е. каждый тридцатый вызов этого прерывания указывает на то, что прошло 1/2 секунды. |
Наша программа имеет счетчик, который увеличивается при каждом вызове подпрограммы обработки прерывания (поскольку сначала выполняется наша подпрограмма, а затем уже подпрограмма обработки прерывания), и если этот счетчик получает значение 29, то он обнуляется и выводится новое время. | Наша программа имеет счетчик, который увеличивается при каждом вызове подпрограммы обработки прерывания (поскольку сначала выполняется наша подпрограмма, а затем уже подпрограмма обработки прерывания), и если этот счетчик получает значение 29, то он обнуляется и выводится новое время. | ||
Строка 315: | Строка 315: | ||
Приводимая ниже программа написана в мнемонике Intel 8080. | Приводимая ниже программа написана в мнемонике Intel 8080. | ||
- | ``` | + | <code> |
- | ┌───────────────────────────────────────────── | + | |
MSX.M-80 1.00 01-Apr-85 PAGE 1 | MSX.M-80 1.00 01-Apr-85 PAGE 1 | ||
;-------------------------------------------- | ;-------------------------------------------- | ||
Строка 450: | Строка 449: | ||
0095 PrgEnd EQU $-1 ; ОТНОСИТЕЛЬНЫЙ АДРЕС КОНЦА | 0095 PrgEnd EQU $-1 ; ОТНОСИТЕЛЬНЫЙ АДРЕС КОНЦА | ||
end | end | ||
- | └───────────────────────────────────────────── | + | </code> |
- | ``` | + | |
{{anchor:n33}} | {{anchor:n33}} | ||
Строка 457: | Строка 455: | ||
Еще одна возможность макрогенерации — использование макрокоманд. В этом случае группе команд дается имя, и каждое использование этого имени в тексте будет означать подстановку соответствующей группы команд в текст. Описание макрокоманды называют макроопределением. Оно выглядит следующим образом: | Еще одна возможность макрогенерации — использование макрокоманд. В этом случае группе команд дается имя, и каждое использование этого имени в тексте будет означать подстановку соответствующей группы команд в текст. Описание макрокоманды называют макроопределением. Оно выглядит следующим образом: | ||
- | ``` | + | <code> |
имя MACRO параметры | имя MACRO параметры | ||
команды-ассемблера | команды-ассемблера | ||
ENDM | ENDM | ||
- | ``` | + | </code> |
Список параметров может отсутствовать. Тогда использование имени макрокоманды в тексте будем обозначать просто подстановку вместо него соответствующей группы команд. | Список параметров может отсутствовать. Тогда использование имени макрокоманды в тексте будем обозначать просто подстановку вместо него соответствующей группы команд. | ||
Например, имеется исходный текст: | Например, имеется исходный текст: | ||
- | ``` | + | <code> |
.Z80 | .Z80 | ||
SHIFT MACRO | SHIFT MACRO | ||
Строка 480: | Строка 478: | ||
RET | RET | ||
END | END | ||
- | ``` | + | </code> |
- | После его трансляции M80 получим: | + | После его трансляции [[msx:macro-80_assembler:macro-80_assembler|M80]] получим: |
- | ``` | + | <code> |
- | ┌─────────────────────────── | + | |
MSX.M-80 1.00 01-Apr-85 PAGE 1 | MSX.M-80 1.00 01-Apr-85 PAGE 1 | ||
.Z80 | .Z80 | ||
Строка 509: | Строка 506: | ||
000E' C9 RET | 000E' C9 RET | ||
END | END | ||
- | └──────────────────────────────── | + | </code> |
- | ``` | + | |
Если в заголовке макрокоманды были указаны параметры, то вместо них в тексте будут подставлены те значения, которые были использованы при вызове макрокоманды. Например, | Если в заголовке макрокоманды были указаны параметры, то вместо них в тексте будут подставлены те значения, которые были использованы при вызове макрокоманды. Например, | ||
- | ``` | + | <code> |
- | ┌───────────────────────────── | + | |
'bcd-hex convrt' MSX.M-80 1.00 01-Apr-85 PAGE 1 | 'bcd-hex convrt' MSX.M-80 1.00 01-Apr-85 PAGE 1 | ||
.Z80 | .Z80 | ||
Строка 551: | Строка 546: | ||
0018' C9 RET | 0018' C9 RET | ||
END | END | ||
- | └──────────────────────────────── | + | </code> |
- | ``` | + | |
- | ### Локальные метки макрокoманды | + | ==== Локальные метки макрокoманды ==== |
Возможны случаи, когда в теле макрокоманды нужно использовать метки. Использовать обычную метку нельзя, потому что при втором вызове макрокоманды появится ошибка "повторно определенная метка". | Возможны случаи, когда в теле макрокоманды нужно использовать метки. Использовать обычную метку нельзя, потому что при втором вызове макрокоманды появится ошибка "повторно определенная метка". | ||
Макроассемблер позволяет обойти это ограничение при помощи использования локальных меток макрокоманды. Вместо таких меток макроассемблер подставляет свои метки особого вида в диапазоне | Макроассемблер позволяет обойти это ограничение при помощи использования локальных меток макрокоманды. Вместо таких меток макроассемблер подставляет свои метки особого вида в диапазоне | ||
- | ``` | + | |
+ | FIXME | ||
+ | <code> | ||
..0000 Ў ..FFFF. | ..0000 Ў ..FFFF. | ||
- | ``` | + | </code> |
- | ### Рассмотрим пример с использованием локальных макрометок. | + | Рассмотрим пример с использованием локальных макрометок. |
- | ``` | + | <code> |
- | ┌──────────────────────────────── | + | |
MSX.M-80 1.00 01-Apr-85 PAGE 1 | MSX.M-80 1.00 01-Apr-85 PAGE 1 | ||
.Z80 | .Z80 | ||
Строка 590: | Строка 585: | ||
0018' C9 RET | 0018' C9 RET | ||
END | END | ||
- | └──────────────────────────────── | + | </code> |
- | ``` | + | |
- | ### Дополнительные возможности макрокоманд | + | ==== Дополнительные возможности макрокоманд ==== |
- | Во время компиляции можно использовать так называемые переменные времени компиляции. Для присваивания значения такой переменной используется директива SET: | + | Во время компиляции можно использовать так называемые переменные времени компиляции. Для присваивания значения такой переменной используется директива ''SET'': |
- | ``` | + | <WRAP group> |
- | имя SET выражение. | + | <WRAP half column> |
- | ``` | + | <code> |
+ | имя SET выражение | ||
+ | </code> | ||
+ | </WRAP> | ||
- | Для управления печатью листинга макроассемблера можно использовать директивы: | + | <WRAP half column> |
+ | . | ||
+ | </WRAP> | ||
+ | </WRAP> | ||
- | - LALL — выводит полный текст макрорасширения; | + | |
- | - SALL — только объектный код расширения без текста; | + | Для управления печатью листинга макроассемблера можно использовать директивы: |
- | - XALL — выводит те строки, которые генерируют текст. | + | * ''LALL'' — выводит полный текст макрорасширения; |
+ | * ''SALL'' — только объектный код расширения без текста; | ||
+ | * ''XALL'' — выводит те строки, которые генерируют текст. | ||
Операции: | Операции: | ||
- | - & — связывание метки и параметра, например, ERROR&X; | + | * & — связывание метки и параметра, например, ''ERROR&X''; |
- | - ;; — макрокомментарий; | + | * ;; — макрокомментарий; |
- | - ! — означает, что за ним — литерал. Например, "!;" означает символ точка с запятой. | + | * ! — означает, что за ним — литерал. Например, "!;" означает символ точка с запятой. |
- | - % — преобразование выражения в число. Например, %X+Y. | + | * % — преобразование выражения в число. Например, %X+Y'. |
Строка 619: | Строка 621: | ||
Желаем Вам успехов в программировании и надеемся, что эта книга предоставила Вам ответы на многие вопросы, касающиеся системы MSX-2. Авторы будут благодарны за все замечания и предложения по содержанию книги. | Желаем Вам успехов в программировании и надеемся, что эта книга предоставила Вам ответы на многие вопросы, касающиеся системы MSX-2. Авторы будут благодарны за все замечания и предложения по содержанию книги. | ||
- | |||
---- | ---- | ||
Строка 626: | Строка 627: | ||
- | {{tag>MSX assembler Programming Book_apguidefb on_github}} | + | {{tag>MSX Book_apguidefb on_github}} |