Команды ассемблера


Содержание

Основные команды языка ассемблер

По назначению можно выделить команды (в скобках приводятся примеры мнемонических кодов операций команд ассемблера ПК типа IBM PC):

l выполнения арифметических операций (ADD и ADC — сложения и сложения с переносом, SUB и SBB — вычитания и вычитания с заемом, MUL и IMUL — умножения без знака и со знаком, DIV и IDIV — деления без знака и со знаком, CMP — сравнения и т. д.);

l выполнения логических операций (OR, AND, NOT, XOR, TEST и т. д.);

l пересылки данных (MOV — переслать, XCHG — обменять, IN — ввести в микропроцессор, OUT — вывести из микропроцессора и т. д.);

l передачи управления (ветвления программы: JMP — безусловного перехода, CALL — вызова процедуры, RET — возврата из процедуры, J* — условного перехода, LOOP — управления циклом и т. д.);

l обработки строк символов (MOVS — пересылки, CMPS — сравнения, LODS — загрузки, SCAS — сканирования. Эти команды обычно используются с префиксом (модификатором повторения) REP;

l прерывания работы программы (INT — программные прерывания, INTO — условного прерывания при переполнении, IRET — возврата из прерывания);

l управления микропроцессором (ST* и CL* — установки и сброса флагов, HLT — останова, WAIT — ожидания, NOP — холостого хода и т. д.).

С полным списком команд ассемблера можно познакомиться в работах [1, 10, 35].

Команды пересылки данных

l MOV dst, src — пересылка данных (move — переслать из src в dst).

Пересылает[1]: один байт (если src и dst имеют формат байта) или одно слово (если src и dst имеют формат слова) между регистрами или между регистром и памятью, а также заносит непосредственное значение в регистр или в память.

Операнды dst и src должны иметь одинаковый формат — байт или слово.

Src могут иметь тип: r (register) — регистр, m (memory) — память, i (impedance) — непосредственное значение. Dst могут быть типа r, m. Нельзя в одной команде использовать операнды: rsegm совместно с i; два операнда типа m и два операнда типа rsegm). Операнд i может быть и простым выражением:

mov AX, (152 + 101B) / 15

Вычисление выражения выполняется только при трансляции. Флаги не меняет.

l PUSH src — занесение слова в стек (pushпротолкнуть; записать в стек изsrc). Помещает в вершину стека содержимое src — любого 16-битового регистра (в том числе и сегментного) или двух ячеек памяти, содержащих 16-битовое слово. Флаги не меняются;

l POP dst — извлечение слова из стека (pop — вытолкнуть; считать из стека в dst). Снимает слово с вершины стека и помещает его в dst — любой 16-битовый регистр (в том числе и сегментный) или в две ячейки памяти. Флаги не меняются.

В командах PUSH и POP операнды dst и src могут быть только типов r и m.

Дата добавления: 2020-04-02 ; просмотров: 2171 ; ЗАКАЗАТЬ НАПИСАНИЕ РАБОТЫ

Будьте всегда
в Настроении

От Masterweb

В статье будут рассмотрены основы языка ассемблер применительно к архитектуре win32. Он представляет собой символическую запись машинных кодов. В любой электронно-вычислительной машине самым низким уровнем является аппаратный. Здесь управление процессами происходит командами или инструкциями на машинном языке. Именно в этой области ассемблеру предназначено работать.

Программирование на ассемблер

Написание программы на ассемблере — крайне трудный и затратный процесс. Чтобы создать эффективный алгоритм, необходимо глубокое понимание работы ЭВМ, знание деталей команд, а также повышенное внимание и аккуратность. Эффективность — это критический параметр для программирования на ассемблер.

Главное преимущество языка ассемблер в том, что он позволяет создавать краткие и быстрые программы. Поэтому используется, как правило, для решения узкоспециализированных задач. Необходим код, работающий эффективно с аппаратными компонентами, или нужна программа, требовательная к памяти или времени выполнения.

Регистры

Регистрами в языке ассемблер называют ячейки памяти, расположенные непосредственно на кристалле с АЛУ (процессор). Особенностью этого типа памяти является скорость обращения к ней, которая значительно быстрее оперативной памяти ЭВМ. Она также называется сверхбыстрой оперативной памятью (СОЗУ или SRAM).

Существуют следующие виды регистров:

  1. Регистры общего назначения (РОН).
  2. Флаги.
  3. Указатель команд.
  4. Регистры сегментов.

Есть 8 регистров общего назначения, каждый размером в 32 бита.

Доступ к регистрам EAX, ECX, EDX, EBX может осуществляться в 32-битовом режиме, 16-битовом — AX, BX, CX, DX, а также 8-битовом — AH и AL, BH и BL и т. д.

Буква «E» в названиях регистров означает Extended (расширенный). Сами имена же связаны с их названиями на английском:

  • Accumulator register (AX) — для арифметических операций.
  • Counter register (CX) — для сдвигов и циклов.
  • Data register (DX) — для арифметических операций и операций ввода/вывода.
  • Base register (BX) — для указателя на данные.
  • Stack Pointer register (SP) — для указателя вершины стека.
  • Stack Base Pointer register (BP) — для индикатора основания стека.
  • Source Index register (SI) — для указателя отправителя (источника).
  • Destination Index register (DI) — для получателя.

Специализация РОН языка ассемблер является условной. Их можно использовать в любых операциях. Однако некоторые команды способны применять только определенные регистры. Например, команды цикла используют ESX для хранения значения счетчика.

Регистр флагов. Под этим подразумевается байт, который может принимать значения 0 и 1. Совокупность всех флагов (их порядка 30) показывают состояние процессора. Примеры флагов: Carry Flag (CF) — Флаг переноса, Overflow Flag (OF) — переполнения, Nested Flag (NT) — флаг вложенности задач и многие другие. Флаги делятся на 3 группы: состояние, управление и системные.

Указатель команд (EIP — Instruction Pointer). Данный регистр содержит адрес инструкции, которая должна быть выполнена следующей, если нет иных условий.

Регистры сегментов (CS, DS, SS, ES, FS, GS). Их наличие в ассемблере продиктовано особым управлением оперативной памятью, чтобы увеличить ее использование в программах. Благодаря им можно было управлять памятью размером до 4 Гб. В архитектуре Win32 необходимость в сегментах отпала, но названия регистров сохранились и используются по-другому.

Это область памяти, выделенная для работы процедур. Особенность стека заключается в том, что последние данные, записанные в него, доступны для чтения первыми. Или иными словами: первые записи стека извлекаются последними. Представить этот процесс себе можно в качестве башни из шашек. Чтобы достать шашку (нижнюю шашку в основание башни или любую в середине) нужно сначала снять все, которые лежат сверху. И, соответственно, последняя положенная на башню шашка, при разборе башни снимается первой. Такой принцип организации памяти и работы с ней продиктован ее экономией. Стек постоянно очищается и в каждый момент времени одна процедура использует его.

Идентификаторы, целые числа, символы, комментарии, эквивалентность

Идентификатор в языке программирования ассемблер имеет такой же смысл, как и в любом другом. Допускается использование латинских букв, цифр и символов «_», «.», «?», «@», «$». При этом прописные и строчные буквы эквивалентны, а точка может быть только первым символом идентификатора.

Целые числа в ассемблере можно указывать в системах отсчета с основаниями 2, 8, 10 и 16. Любая другая запись чисел будет рассматриваться компилятором ассемблера в качестве идентификатора.

В записи символьных данных допускается использовать как апострофы, так и кавычки. Если в символьной строке требуется указать один из них, то правила следующие:

  • в строке, заключенной в апострофы, кавычки указываются один раз, апостроф — дважды: ‘can»t’, ‘ he said «to be or not to be» ‘;
  • для строки, заключенной в кавычки, правило обратное: дублируются кавычки, апострофы указываются как есть: «couldn’t», » My favourite bar is «»Black Cat»» «.

Для указания комментирования в языке ассемблер используется символ точка с запятой — «;». Допустимо использовать комментарии как в начале строк, так и после команды. Заканчивается комментарий переводом строки.

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

Таким образом в программе все вхождения будут заменяться на , на месте которого допустимо указывать целое число, адрес, строку или другое имя. Директива EQU похожа по своей работе на #define в языке С++.

Директивы данных

Языки высокого уровня (C++, Pascal) являются типизированными. То есть, в них используются данные, имеющие определенный тип, имеются функции их обработки и т. д. В языке программирования ассемблер подобного нет. Существует всего 5 директив для определения данных:

  1. DB — Byte: выделить 1 байт под переменную.
  2. DW — Word: выделить 2 байта.
  3. DD — Double word: выделить 4 байта.
  4. DQ — Quad word: выделить 8 байтов.
  5. DT — Ten bytes: выделить 10 байтов под переменную.

Буква D означает Define.

Любая директива может быть использована для объявления любых данных и массивов. Однако для строк рекомендуется использовать DB.

В качестве операнда допустимо использовать числа, символы и знак вопрос — «?», обозначающий переменную без инициализации. Рассмотрим примеры:

Команды (инструкции)

Синтаксис команд ассемблера или инструкций ассемблера выглядит следующим образом:

Метка (label:) обязательно завершается двоеточием и может располагаться в отдельной строке. Метки используются для того, чтобы ссылаться на команды внутри программы.

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

В роли операндов команды могут выступать:

  • регистры, обращение к которым происходит по их именам;
  • константы;
  • адреса.

Подробнее об адресах

Адрес может передаваться несколькими способами:

  1. В виде имени переменной, которая в ассемблере является синонимом адреса.
  2. Если переменная является массивом, то обращение к элементу массива происходит через имя его переменной и смещения. Для этого существует 2 формы: [ + ] и [ ]. Следует учитывать, что смещение — это не индекс в массиве, а размер в байтах. Программисту самому необходимо понимать, на сколько нужно сделать смещение в байтах, чтобы получить нужный элемент массива.
  3. Можно использовать регистры. Для обращения к памяти, в которой хранится регистр, нужно использовать квадратные скобки: [ebx], [edi].
  4. [] — квадратные скобки допускают применение сложных выражений внутри себя для вычисления адреса: [esi + 2*eax].

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

Помимо этого, в ассемблер существуют сокращения: r — для регистров, m — для памяти и i — для операнда. Эти сокращения используются с числами 8, 16 и 32 для указания размера операнда: r8, m16, i32 и т. д.

Команда mov или пересылка

Данная инструкция является основной среди команд ассемблера. Она позволяет записывать в регистр значение другого регистра, ячейки памяти или константы. Она же осуществляет запись в ячейку памяти значения регистра или константы. Синтаксис команды:

В процессоре существует и другие команды для реализации пересылки. Например, XCHG — команда обмена операндов значениями. Но с точки зрения программиста, все они реализованы через команду базовую MOV. Рассмотрим примеры:

В виде операнда может выступать как регистр, так и ячейка памяти. Однако если содержимое двух регистров можно переставить, то двух ячеек памяти — нет. Следует внимательно следить за тем, чтобы операнды имели одинаковый размер. Также заметим, что команда MOV не изменяет значения флагов.

Инструментарий

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

  • Borland Turbo Assembler (TASM) — один из самых популярных инструментов. Хорошо подходит для разработки под DOS и плохо — под Windows.
  • Microsoft Macro Assembler (MASM) — это пакет для разработки на ассемблере в среде Windows. Существует как отдельно, так и в виде встроенной функции в среде Visual Studio. Ассемблер и языки высокого уровня часто совместимы. В том смысле, что последние могут использовать ассемблер напрямую. Например, С++.
  • Netwide Assembler (NASM) — популярный свободный ассемблер для архитектуры Intel.

Существует множество инструментов. При этом следует сделать особую пометку о том, что нет единого стандарта синтаксиса ассемблера. Есть 2 наиболее применимых: AT&T-синтаксис, ориентированный на процессоры производства не Intel, и, соответственно, Intel-синтаксис.

Несмотря на кажущуюся сложность, ассемблер является простым языком программирования, понять который не составляет труда. Поэтому можно смело использовать учебную литературу на подобии «ассемблер для чайников» и изучать этот замечательный язык.

Язык ассемблер. Команды и основы ассемблера

В статье будут рассмотрены основы языка ассемблер применительно к архитектуре win32. Он представляет собой символическую запись машинных кодов. В любой электронно-вычислительной машине самым низким уровнем является аппаратный. Здесь управление процессами происходит командами или инструкциями на машинном языке. Именно в этой области ассемблеру предназначено работать.

Программирование на ассемблер

Написание программы на ассемблере — крайне трудный и затратный процесс. Чтобы создать эффективный алгоритм, необходимо глубокое понимание работы ЭВМ, знание деталей команд, а также повышенное внимание и аккуратность. Эффективность — это критический параметр для программирования на ассемблер.

Главное преимущество языка ассемблер в том, что он позволяет создавать краткие и быстрые программы. Поэтому используется, как правило, для решения узкоспециализированных задач. Необходим код, работающий эффективно с аппаратными компонентами, или нужна программа, требовательная к памяти или времени выполнения.

Регистры

Регистрами в языке ассемблер называют ячейки памяти, расположенные непосредственно на кристалле с АЛУ (процессор). Особенностью этого типа памяти является скорость обращения к ней, которая значительно быстрее оперативной памяти ЭВМ. Она также называется сверхбыстрой оперативной памятью (СОЗУ или SRAM).

Существуют следующие виды регистров:

  1. Регистры общего назначения (РОН).
  2. Флаги.
  3. Указатель команд.
  4. Регистры сегментов.

Есть 8 регистров общего назначения, каждый размером в 32 бита.

Доступ к регистрам EAX, ECX, EDX, EBX может осуществляться в 32-битовом режиме, 16-битовом — AX, BX, CX, DX, а также 8-битовом — AH и AL, BH и BL и т. д.

Буква «E» в названиях регистров означает Extended (расширенный). Сами имена же связаны с их названиями на английском:

  • Accumulator register (AX) — для арифметических операций.
  • Counter register (CX) — для сдвигов и циклов.
  • Data register (DX) — для арифметических операций и операций ввода/вывода.
  • Base register (BX) — для указателя на данные.
  • Stack Pointer register (SP) — для указателя вершины стека.
  • Stack Base Pointer register (BP) — для индикатора основания стека.
  • Source Index register (SI) — для указателя отправителя (источника).
  • Destination Index register (DI) — для получателя.

Специализация РОН языка ассемблер является условной. Их можно использовать в любых операциях. Однако некоторые команды способны применять только определенные регистры. Например, команды цикла используют ESX для хранения значения счетчика.

Регистр флагов. Под этим подразумевается байт, который может принимать значения 0 и 1. Совокупность всех флагов (их порядка 30) показывают состояние процессора. Примеры флагов: Carry Flag (CF) — Флаг переноса, Overflow Flag (OF) — переполнения, Nested Flag (NT) — флаг вложенности задач и многие другие. Флаги делятся на 3 группы: состояние, управление и системные.

Указатель команд (EIP — Instruction Pointer). Данный регистр содержит адрес инструкции, которая должна быть выполнена следующей, если нет иных условий.

Регистры сегментов (CS, DS, SS, ES, FS, GS). Их наличие в ассемблере продиктовано особым управлением оперативной памятью, чтобы увеличить ее использование в программах. Благодаря им можно было управлять памятью размером до 4 Гб. В архитектуре Win32 необходимость в сегментах отпала, но названия регистров сохранились и используются по-другому.

Это область памяти, выделенная для работы процедур. Особенность стека заключается в том, что последние данные, записанные в него, доступны для чтения первыми. Или иными словами: первые записи стека извлекаются последними. Представить этот процесс себе можно в качестве башни из шашек. Чтобы достать шашку (нижнюю шашку в основание башни или любую в середине) нужно сначала снять все, которые лежат сверху. И, соответственно, последняя положенная на башню шашка, при разборе башни снимается первой. Такой принцип организации памяти и работы с ней продиктован ее экономией. Стек постоянно очищается и в каждый момент времени одна процедура использует его.

Идентификаторы, целые числа, символы, комментарии, эквивалентность

Идентификатор в языке программирования ассемблер имеет такой же смысл, как и в любом другом. Допускается использование латинских букв, цифр и символов «_», «.», «?», «@», «$». При этом прописные и строчные буквы эквивалентны, а точка может быть только первым символом идентификатора.

Целые числа в ассемблере можно указывать в системах отсчета с основаниями 2, 8, 10 и 16. Любая другая запись чисел будет рассматриваться компилятором ассемблера в качестве идентификатора.

В записи символьных данных допускается использовать как апострофы, так и кавычки. Если в символьной строке требуется указать один из них, то правила следующие:

  • в строке, заключенной в апострофы, кавычки указываются один раз, апостроф — дважды: ‘can»t’, ‘ he said «to be or not to be» ‘;
  • для строки, заключенной в кавычки, правило обратное: дублируются кавычки, апострофы указываются как есть: «couldn’t», » My favourite bar is «»Black Cat»» «.

Для указания комментирования в языке ассемблер используется символ точка с запятой — «;». Допустимо использовать комментарии как в начале строк, так и после команды. Заканчивается комментарий переводом строки.

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

Таким образом в программе все вхождения будут заменяться на , на месте которого допустимо указывать целое число, адрес, строку или другое имя. Директива EQU похожа по своей работе на #define в языке С++.

Директивы данных

Языки высокого уровня (C++, Pascal) являются типизированными. То есть, в них используются данные, имеющие определенный тип, имеются функции их обработки и т. д. В языке программирования ассемблер подобного нет. Существует всего 5 директив для определения данных:

  1. DB — Byte: выделить 1 байт под переменную.
  2. DW — Word: выделить 2 байта.
  3. DD — Double word: выделить 4 байта.
  4. DQ — Quad word: выделить 8 байтов.
  5. DT — Ten bytes: выделить 10 байтов под переменную.

Буква D означает Define.

Любая директива может быть использована для объявления любых данных и массивов. Однако для строк рекомендуется использовать DB.

В качестве операнда допустимо использовать числа, символы и знак вопрос — «?», обозначающий переменную без инициализации. Рассмотрим примеры:

Команды (инструкции)

Синтаксис команд ассемблера или инструкций ассемблера выглядит следующим образом:

Метка (label:) обязательно завершается двоеточием и может располагаться в отдельной строке. Метки используются для того, чтобы ссылаться на команды внутри программы.

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

В роли операндов команды могут выступать:

  • регистры, обращение к которым происходит по их именам;
  • константы;
  • адреса.

Подробнее об адресах

Адрес может передаваться несколькими способами:

  1. В виде имени переменной, которая в ассемблере является синонимом адреса.
  2. Если переменная является массивом, то обращение к элементу массива происходит через имя его переменной и смещения. Для этого существует 2 формы: [ + ] и [ ]. Следует учитывать, что смещение — это не индекс в массиве, а размер в байтах. Программисту самому необходимо понимать, на сколько нужно сделать смещение в байтах, чтобы получить нужный элемент массива.
  3. Можно использовать регистры. Для обращения к памяти, в которой хранится регистр, нужно использовать квадратные скобки: [ebx], [edi].
  4. [] — квадратные скобки допускают применение сложных выражений внутри себя для вычисления адреса: [esi + 2*eax].

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

Помимо этого, в ассемблер существуют сокращения: r — для регистров, m — для памяти и i — для операнда. Эти сокращения используются с числами 8, 16 и 32 для указания размера операнда: r8, m16, i32 и т. д.

Команда mov или пересылка

Данная инструкция является основной среди команд ассемблера. Она позволяет записывать в регистр значение другого регистра, ячейки памяти или константы. Она же осуществляет запись в ячейку памяти значения регистра или константы. Синтаксис команды:

В процессоре существует и другие команды для реализации пересылки. Например, XCHG — команда обмена операндов значениями. Но с точки зрения программиста, все они реализованы через команду базовую MOV. Рассмотрим примеры:

В виде операнда может выступать как регистр, так и ячейка памяти. Однако если содержимое двух регистров можно переставить, то двух ячеек памяти — нет. Следует внимательно следить за тем, чтобы операнды имели одинаковый размер. Также заметим, что команда MOV не изменяет значения флагов.

Инструментарий

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

  • Borland Turbo Assembler (TASM) — один из самых популярных инструментов. Хорошо подходит для разработки под DOS и плохо — под Windows.
  • Microsoft Macro Assembler (MASM) — это пакет для разработки на ассемблере в среде Windows. Существует как отдельно, так и в виде встроенной функции в среде Visual Studio. Ассемблер и языки высокого уровня часто совместимы. В том смысле, что последние могут использовать ассемблер напрямую. Например, С++.
  • Netw >

Существует множество инструментов. При этом следует сделать особую пометку о том, что нет единого стандарта синтаксиса ассемблера. Есть 2 наиболее применимых: AT&T-синтаксис, ориентированный на процессоры производства не Intel, и, соответственно, Intel-синтаксис.

Несмотря на кажущуюся сложность, ассемблер является простым языком программирования, понять который не составляет труда. Поэтому можно смело использовать учебную литературу на подобии «ассемблер для чайников» и изучать этот замечательный язык.

Арифметические операции Ассемблер. Команды Ассемблера

Введение в язык Ассемблер

Для того, чтобы программировать на Assembler, необходимо:

Программа MASM_v9.0 или MASM_v10.0
Отладчик, например: OLLYDBG.EXE
В установленном месте, где находится программа MASM, создаете файл: aaa.bat

Я выбрал такое название (aaa.bat) для того, чтобы она была в самом верху. И вы могли всегда его видеть. В этом aaa.bat вносите такую информацию:

ml /c /coff «work.asm»
link /SUBSYSTEM:CONSOLE «work.obj»

work.asm — это имя программы, которую нужно компилировать. После ввода этой информации и сохранения можно приступать к программированию.

Ассемблер имеет:

— директиву определения типа микропроцессора,
— метку начала программы,
— тело программы,
— метку окончания программы

В языке Ассемблер есть переменые разных типов: знаковые и беззнаковые форматытипов Shortlnt (signed char), Byte (unsigned char), Integer (int), Word (unsigned int) и т. д.

Напишем программу вычисления выражения: a – e/b – de, где:

a = 5;
b = 27;
c = 86;
е = 1986;
d = 1112;

и сохраним ее там же, где и aaa.bat: work.asm. Если мы хотил откомпилировать другую программу, то нужно в aaa.bat изменить имя файлов, т. е. вместо workзаменить на . имя. И сохранить его. Если программа не содержит синтаксические ошибки, то должен получиться файл с расширением exe.

Программа:

.686 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
; но соглашения ОС Windows

.data ; директива определения данных
_a dw 5 ; запись в 16-разрядный амбарчик памяти с именем _а числа 5
_b dw 27 ; запись _b = 16h
_c dw 86 ; запись _c = 56h
_e dw 1986 ; запись _e = 7c2h
_d dw 1112 ; запись _d = 458
res dw 0 ; резервирование памяти для сохранения переменной res

.code ; директива начала сегмента команд
start:
mov edx,0 ; очистка регистров
mov ebx,0
mov ecx,0
mov ах,_e ; в регистр ах заносим число _e = 7c2h
mul _d ; умножаем _e на _d
SHL edx,16 ; делаем здвиг на 16
mov dx,ax
push edx ; бросаем значение в стек
mov edx,0
mov ах,_e
mov cx,_b
div cx ; делим ах на cx
pop ecx ; достаем из стека значене
sub ecx,eax ; отнимает
mov ах,_a
sub eax,ecx
mov res, eax
ret ; возвращение управления ОС
end start ; окончание программы с именем _start

Результат работы программы:

как мы видим, комментарии ставятся после точки с запятой.

mov куда, откуда — это команда перевылки

mul _d — это команда умнжения регистра ax на _d. Результат попадает в ax

shl edx,16 — команда здвига на 16 разрядов

div cx — команда деления ах на cx. Результат попадает в ax

pop ecx — команда достает из стека значене

sub ecx,eax — команда отнимает значение ecx — eax. Результат попадает в ecx

Арифметические операции Ассемблер. Команды Ассемблера

Программирование арифметических выражений в языке Ассемблер происходит через некоторые команды такие, как: mul, div, sub, add. Эти команды называются командами арифметических операций.

Mul – команда умножения. Она умножает регистр ax на то, что стоит после нее. Результат заносится в ax.
Div – команда деления. Она делит регистр axна то, что стоит после нее. Результат заносится в ax.
Add – команда сложения. Слаживает два числа. Результат заносится в первый регистр.
Sub – команда вычитания. Вычитает два числа. Результат заносится в первый регистр.

Пример: Написать программу на ассемблере вычисления выражения: а – e/b – de;
где а =5;
b =27;
c = 86;
е =1986;
d =1112;
Результат вычисления выражения сохранить в памяти. Навести значение и порядок размещения данные в памяти.

Текст программы

.686 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
; но соглашения ОС Windows

.data ; директива определения данные
_a dw 5 ; запись в 16-разрядный амбарчик памяти с именем _а числа 5
_b dw 27 ; запись _b = 16h
_c dw 86 ; запись _c = 56h
_e dw 1986 ; запись _e = 7C2h
_d dw 1112 ; запись _d = 458
res dw 0 ; резервирование памяти для сохранения переменной res

.code ; директива начала сегмента команд
start:
mov edx,0 ; очистка регистров
mov ebx,0 ; очистка регистров
mov ecx,0 ; очистка регистров
mov ах,_e ; в регистр ах заносим число _e = 7C2h
mul _d ; множим _e и _d
SHL edx,16 ; делаем здвиг на 16
mov dx,ax
push edx ; бросаем значение в стек
mov edx,0
mov ах,_e
mov cx,_b
div cx ; делим ах с cx
pop ecx ; достаем из стеку значения
sub ecx,eax ; отнимаем
mov ах,_a
sub eax,ecx
mov res, eax
ret ; возвращение управление ОС
end start ; окончание программы с именем _start

Результат работы программы

Двумерные массивы на Ассемблере. Ассемблер двумерными массивами примеры

В данном уроке паказывается ввод элементов в двумерный массив. Приводится пример нахождение максимального элемента массива в ассемблере. И происходит вывод в MessageBox.

Пример: Ввести двумерный массив размером 7 х 4. Найти наибольший элемент двумерного массива. Удалить строку с максимальным элементом.

Текст программы:

.686 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc
include \masm32\include\msvcrt.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\fpu.lib

.data ; директива определения данные
_c dd 28
sum dd 0
max dd 0 ; переменная для максимального числа

frmt db «%d»,0
buf db 30 dup(?)
stdout DWORD ?
stdin DWORD ?
cRead dd ?
temp dd ?
mas1 dd 28 dup(0)
nomer dd 0
st1 db «Vvesty masiv: »
st2 db «Вывод результата удаления», 0
st3 db 10 dup(0)
ifmt db «Удалена %d строка. Внимание. Проверьте правильность ввода, чтобы результат был правильным»,0

.code ; директива начала кода программы
_start:
lea esi, mas1 ; загрузка адреса начала массива
mov ecx,_c
m1:
mov ebx,ecx
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov stdout,eax
invoke GetStdHandle,STD_INPUT_HANDLE
mov stdin,eax
invoke WriteConsoleA,stdout,ADDR st1,14,NULL,NULL ; VIVOD ST1
invoke ReadConsole,stdin,ADDR buf,20,ADDR cRead,NULL ; чтения числа как символ
invoke crt_atoi,ADDR buf ; преобразовать символ в число
mov [esi],eax
add esi,4
mov ecx,ebx
loop m1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

mov ecx,_c
lea esi, mas1 ; загрузка адреса начала массива
mov eax [esi] ; загрузка числа
m3:
.IF(eax>max) ; условие
mov max,eax
add esi,4 ; расчет адреса нового числа
mov eax[esi]
loop m3

.ELSE ; иначе
add esi,4 ; расчет адреса нового числа
mov eax[esi]
loop m3 ; перейти, если ecx не равен 0

.ENDIF ; окончание директивы высокого уровня

mov ecx,_c
lea esi, mas1 ; загрузка адреса начала массива
mov eax [esi] ; загрузка числа
m4:

.IF(eax == max) ; условие
inc nomer
add esi,4 ; расчет адреса нового числа
mov eax[esi]
jmp m5
loop m4

.ELSE ; иначе
inc nomer
add esi,4 ; расчет адреса нового числа
mov eax[esi]
loop m4 ; перейти, если ecx не равен 0

.ENDIF ; окончание директивы высокого уровня

m5:
.IF(nomer ; структура с именем str1
str2 DATE1 ; структура с именем str2
str3 DATE1 ; структура с именем str2
st1 db » Вывод максимальных чисел «,0
st2 db 180 dup(?),0
stemp db 0
stemp2 db 3 dup(?),0
st4 db » Нажмите Ок»,0
st3 db «-й ряд имеет максимальное число = »
kol3 = $ — st3
kol4 = $ — st4
ifmt db «%d «,0
.code ; директива начала сегмента-данных
start: ; метка начала программы с именем start
xor edx,edx ; заполнение нулями
mov ebx,3 ; загрузка количества строк
lea esi, str1 ; загрузка адреса первой строки структуры
lea edi,st2
m1: mov ecx,4 ; количество элементов в строке
mov max,0
m2: mov al[esi] ; загрузка элемента из строки структуры
.IF (al > max)
mov max,al
.ENDIF
jmp m4 ; безусловный переход, если наоборот
m3: add edx,eax ; добавление негативных элементов строки структуры
m4: inc esi ; подготовка адреса нового элемента
loop m2 ; есх := ecx – 1 и переход на m3, если не нуль

mov eax,0
mov al,nomer
invoke wsprintf \ ; API-ФУНКЦИЯ превращения числа
ADDR stemp \ ; адрес буфф., куда будет записан помет. символов
ADDR ifmt \ ; адрес строки превращения формата
eax ; регистр, содержание которого превращается
mov al,stemp
mov [edi],al
inc edi

lea esi, st3
mov ecx,kol3

_m1:
mov al[esi]
mov [edi],al
inc esi
inc edi
loop _m1
mov eax,0
mov al,max

invoke wsprintf \ ; API-ФУНКЦИЯ превращения числа
ADDR stemp2 \ ; адрес буфф., куда будет записан помет. символов
ADDR ifmt \ ; адрес строки превращения формата
eax ; регистр, содержание которого превращается
lea esi, stemp2
mov ecx,3
z1:
mov al[esi]
mov [edi],al
inc edi
inc esi
loop z1

mov al,10
mov [edi],al
inc edi
inc nomer

dec ebx ; ebx := ebx – 1
.IF ebx == 2
lea esi,str2 ; загрузка адреса новой строки
jmp m1 ; переход на новый цикл
.ELSEIF ebx == 1
lea esi,str3 ; загрузка адреса новой строки
jmp m1 ; переход на новый цикл
.ENDIF

mov al,10
mov [edi],al
inc edi
lea esi, st4
mov ecx,kol4
inc esi
_z1:
mov al[esi]
mov [edi],al
inc esi
inc edi
loop _z1

invoke MessageBox \ ; API-ФУНКЦИЯ выведения окна консоли
NULL \ ; hwnd – идентификатор окна
addr st2 \ ; адрес строки, который содержит текст сообщения
addr st1 \ ; адрес строки, который содержит заглавие сообщения
MB_OK ; вид диалогового окна

invoke ExitProcess, 0 ; возвращение управления ОС Windows
end start ; директива окончания программы с именем start

Результат работы программы:

Текст процедуры программы

.686 ; директива определения типа микропроцессора
.model flat ; задание линейной модели памяти
option casemap:none
public _abcd
extern _a:dword, _b:dword, _c:dword,_d:dword
.code ; директива начала программы
_abcd proc ; ab — c/d
mov eax,_a ; пересылка из памяти с именем _а в eax
mov ebx,_b ; пересылка из памяти с именем _b в ebx
mul ebx ; edx, eax := eax ? ebx
mov esi,eax
mov edi,edx
mov eax,_c
mov ebx,_d
xor edx,edx ; подготовление к делению
div ebx
mov ecx,0
sub ecx,edx ; вычитание мелкой части из целого числа
sbb esi,eax ; вычитание целой младшей части
sbb edi,0 ; вычитание позычки, если она есть
ret
_abcd endp
end ; директива окончания программы

Результат работы программы

Массивы в Ассемблере. Программа на Ассемблере. Пример массив элементов

Пример задачи с использованием массива на ассемблере: Заданы массивы Aи Виз N= 8 элементов. Сформировать новый массивСпо правилу: если у элементов Aiи Bi биты 0, 1 и 2 совпадают, то Ci= Аi + Вi.

Текст прогаммы

.686 ; директива определения типа микропроцессора
.model flat, stdcall ; задание линейной модели памяти
; но соглашения ОС Windows
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\fpu.lib
ExitProcess proto:DWORD

.data ; директива определения данные
st1 db «Вывод массива! С», 0
st2 db 10 dup(?),0
ifmt db «%d»,0
masivA db 7,34,34,45,2,6,2-6
masivB db 54,2,7,43,13-7,65,9
masivC db 8 dup(0)
work1 db 0
work2 db 0
prom dd 0

.code ; директива начала кода программы
_start:
mov eax,0
mov ebx,0
mov ecx,8
mov edx,0

lea esi, masivA
lea edi, masivB
lea edx, masivC

M1:
mov prom,ebx
mov al, byte ptr[esi+ebx]
mov bl, byte ptr[edi+ebx]
mov work1, al
mov work2, bl
and eax,07h
and ebx,07h
sub eax,ebx
jz M3

M2:
mov ebx, prom
inc ebx
loop M1
jmp M4

M3:
mov al, work1
mov bl, work2
add al,bl
mov [edx+ebx],al
jmp M2

M4:
mov edx,0
mov ecx,08h
Prom:
lea esi,masivC;
mov al[esi+edx]
cmp al,0
jnz _M2
_M1: inc edx
loop Prom
jmp _M3
_M2:
mov ebx,eax
jmp _M1
_M3:
invoke wsprintf \
ADDR st2 \
ADDR ifmt \
ebx
invoke MessageBox \
NULL \
addr st2 \
addr st1 \
MB_OK
invoke ExitProcess,0
end _start ; окончание программы


Результат работы программы

Макросы в Ассемблере. Примеры задач

Пример: Написать программу с использованием макросовдля вычисления одного из выражений без предыдущего математического упрощения операций:
2x – 3 + 8(2x –3);

Текст программы:

.686 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
; но соглашения ОС Windows
option casemap:none ; отличие малых и больших букв
includelib \masm32\lib\kernel32.lib
ExitProcess proto:dword ; прототип API-функції
mSubB macro x,b ; макрос с именем mSubB
mov al,x
shl al,1 ; занос переменной а
sub al,b ; вычитание а – b
mov res1,al ;; сохранение результата в памяти
endm ; окончание макроса
.data ; директива определения данные
x db 6 ; сохранение в амбарчике памяти, размером в байт операнда 6
b db 3
res1 db 0 ; резервирование памяти для результата res1
res2 dw 0 ; резервирование памяти для результата res2
.code ; директива начала программы
_start: ; метка начала программы с именем _start
xor eax,eax
xor ebx,ebx
mSubB [x][b] ; вызов макроса
mov al,8
mov bl,res1
mul bl
mov bl,al
mSubB [x][b] ; вызов макроса
mov al,res1 ; занос с расширением разрядности
add bx,ax
mov res2,bx ; сохранение остаточного результата
invoke ExitProcess, 0 ; возвращение управления ОС Windows
end _start ; директива окончания программы с именем _start

Результат работы программы:

Файл 1dll.asm

.386
.model flat,stdcall
option casemap:none ; отличие строчных и прописных букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc
include \masm32\include\msvcrt.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\fpu.lib

includelib 1.lib
ExitProcess proto :DWORD
Mas_sum proto :DWORD, :DWORD, :DWORD ; прототип процедуры

.data ; директива определения данные
_c dd 40
sum dd 0
op1 dd 6 ; запись в 32-разрядную память op1
op2 dd 22 ; минимальных предел
frmt db «%d»,0
buf db 30 dup(?)
stdout DWORD ?
stdin DWORD ?
cRead dd ?
temp dd ?
mas1 dd 40 dup(0)

st1 db «Vvesty masiv: »
st2 db «Вывод количества элементов в пределах (6,22) массива! А, 0
st3 db 10 dup(0)
ifmt db «количество = %d»,0
.code ; директива начала кода программы

_start:
lea esi, mas1 ; загрузка адреса начала массива
mov ecx,_c
m1:
mov ebx,ecx
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov stdout,eax
invoke GetStdHandle,STD_INPUT_HANDLE
mov stdin,eax
invoke WriteConsoleA,stdout,ADDR st1,14,NULL,NULL ; VIVOD ST1
invoke ReadConsole,stdin,ADDR buf,20
ADDR cRead,NULL ; чтения числа как символ
invoke crt_atoi,ADDR buf ; преобразовать символ в число
mov [esi],eax
add esi,4
mov ecx,ebx
loop m1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

mov ecx,_c
lea esi, mas1 ; загрузка адреса начала массива
mov eax [esi] ; загрузка числа
m3:
invoke Mas_sum, op1,op2,eax
add sum,ebx
add esi,4 ; расчет адреса нового числа
mov eax[esi]
loop m3

invoke wsprintf \
ADDR st3 \
ADDR ifmt \
ebx
invoke MessageBox \
NULL \
addr st3 \
addr st2 \
MB_OK
invoke ExitProcess,0
ret
end _start ; конец программы

Результат работы программы:

Ассемблер сопроцессор. Примеры задач

Пример 1: Вычислить 6 значений функции:Yn = 4x/(x + 5) (х изменяется от 3 с шагом 1,25). Результат округлить к целому, разместить в памяти и вывести на экран.

1.1 Текст программы

.386 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\fpu.lib

.data ; директива определения данные

_x dd 3 ; сохранение в 32-разрядном амбарчике памяти переменной х
_y dd 0 ; резервирование 32-х разрядов памяти для переменной в
tmp1 dd ? ; резервирование 32-х разрядов памяти для переменной tmp1
tmp2 dd ? ; резервирование 32-х разрядов памяти для переменной tmp2
hod dd 1.25
krok dd 5
_umnoj dd 4 ; умножение на 4
probel dd 09h ; для вывода на экран
res dd 0
ifmt db «Yn = %d»,0
st1 db «Yn = 4x/(x + 5) «,0
st2 dd 10 dup(?),0
st3 dd 10 dup(?),0

.code ; директива начала кода программы
_start: ; директива начала кода программы
lea edi,st2
lea esi,st3
xor eax,eax ; обнуление регистров
xor ebx,ebx
xor ecx,ecx
xor edx,edx
finit ; инициирующее сопроцессора
mov ecx,6
fild _x
m1:
fld st(0)
fiadd krok
fld st(1)
fimul _umnoj
fmul st(0),st(1)
fistp dword ptr [edi]
fistp dword ptr [esi]
fadd hod


lea edi,st2
mov eax[edi+20]

invoke wsprintf \
ADDR st2 \
ADDR ifmt \
eax
invoke MessageBox \
NULL \
addr st2 \
addr st1 \
MB_OK
invoke ExitProcess,0
end _start ; зак?нчення программы

1.2 Результат работы программы

Пример 2 : Определить номер (х) элемента функции: xn =+ 5, при котором сумма элементов превысит 12 000. Результат разместить в памяти и вывести соответствующие сообщения.

2.1 Текст программы

.386 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\fpu.lib

.data ; директива определения данные

_x dd 0 ; сохранение переменной х
_y dd 0 ; резервирование 32-х разрядов памяти для переменной в
tmp1 dd ? ; резервирование 32-х разрядов памяти для переменной tmp1
tmp2 dd ? ; резервирование 32-х разрядов памяти для переменной tmp2
hod dd 1
krok dd 3
plus dd 5
mem dw ?
_MASK equ 0C00h
limit dd 12000
ifmt db «№ = %d»,0
st1 db «Вывод номера елемента»,0
st2 dd 10 dup(?),0
st3 dd 10 dup(?),0

.code ; директива начала кода программы
_start: ; директива начала кода программы
lea edi,st2
lea esi,st3
xor eax,eax ; обнуление регистров
xor ebx,ebx
xor ecx,ecx
xor edx,edx
mov edx,limit
finit ; инициализация сопроцессора
fstcw mem
OR mem,_MASK
fldcw mem
mov ecx,6
m1:
inc _x
fild _x
fild krok
fyl2x
fld st(0)
frndint
fsub st(1),st(0)
frndint
f2xm1
fiadd hod
fldz
fadd st(0),st(2)
f2xm1
fiadd hod
fmul st(0),st(1)
fiadd plus
fistp dword ptr [edi]
fistp dword ptr [esi]
fistp dword ptr [esi]
mov eax[edi]
add ebx,eax
add edi,4
add esi,4
cmp edx,ebx
jns m1

invoke wsprintf \
ADDR st2 \
ADDR ifmt \
eax
invoke MessageBox \
NULL \
addr st2 \
addr st1 \
MB_OK
invoke ExitProcess,0
end _start ; зак?нчення программы

2.2 Результат работы программы

Пример 3: Вычислить 4 значения функции: Y = 3 * log2(x2+1), x изменяется от 0,2 с шагом 0,3.

3.1 Текст программы

.386 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\fpu.lib

.data ; директива определения данные

_x dd 0.2 ; сохранение в 32-разрядном амбарчике памяти переменной х
_y dd 0 ; резервирование 32-х разрядов памяти для переменной в
tmp1 dd ? ; резервирование 32-х разрядов памяти для переменной tmp1
tmp2 dd ? ; резервирование 32-х разрядов памяти для переменной tmp2
hod dd 0.3
umnoj dd 3
const dd 4
mem dw ?
_MASK equ 0C00h
ifmt db «Y = %d»,0
st1 db «Вывод функции»,0
st2 dd 10 dup(?),0
st3 dd 10 dup(?),0

.code ; директива начала кода программы
_start: ; директива начала кода программы
lea edi,st2
lea esi,st3
xor eax,eax ; обнуление регистров
xor ebx,ebx
xor ecx,ecx
xor edx,edx
finit ; инициализания сопроцессора
fstcw mem
OR mem,_MASK
fldcw mem
mov ecx,4

fld _x
fld _x
m1:
fild umnoj
fld st(1)
fmulp st(2),st(0)
fyl2x
fld hod
fadd st(2),st(0)

fistp dword ptr [edi]
dec const
jz m2
fistp dword ptr [esi]
fld st(0)
mov eax[esi]
add edi,4
add esi,4
loop m1
m2:

invoke FpuFLtoA, 0, 10, ADDR st2, SRC1_FPU or SRC2_DIMM
invoke MessageBox, NULL, addr st2, addr st1, MB_OK
invoke ExitProcess, NULL ; возвращение управления ОС Windows
; но освобождение ресурсов

end _start ; директива окончания программы с именем start

Результат работы программы

Общая информация

Здесь представлена информация по ассемблеру всей серии AVR, т.к. все микроконтроллеры этой серии программно совместимы.
Ассемблер – это инструмент, с помощью которого создаётся программа для микроконтроллера. Ассемблер транслирует ассемблируемый исходный код программы в объектный код, который может использоваться в симуляторах или эмуляторах AVR. Также ассемблер генерирует код, который может быть непосредственно введен в программную память микроконтроллера.
При работе с ассемблером нет никакой необходимости в непосредственном соединении с микроконтроллером.

Исходный файл, с которым работает ассемблер, должен содержать мнемоники, директивы и метки.
Перед каждой строкой программы можно ставить метку, которая является алфавитно-цифровой строкой, заканчивающейся двоеточием. Метки используются как указания для безусловного перехода и команд условного перехода.

Строка программы может быть в одной из четырёх форм:

[ Метка:] директива [операнды] [Комментарий]
[ Метка:] команда [операнды] [Комментарий]
Комментарий
Пустая строка

Комментарий имеет следующую форму:

Таким образом любой текст после символа “ ; ” игнорируется ассемблером и имеет значение только для пользователя.

Операнды можно задавать в различных форматах:

— десятичный (по умолчанию): 10,255
— шестнадцатеричный (два способа): 0x0а, $0а
— двоичный: 0b00001010, 0b11111111
— восьмеричный (впереди ноль): 010, 077

Система команд

Система команд микроконтроллеров ATMEL семейства AVR очень большая и в то же время эффективная. Одной из отличительных особенностей микроконтроллеров AVR является то, что почти все команды выполняются за 1 тактовый цикл. Исключение составляют команды перехода. Это существенно увеличивает производительность микроконтроллера даже при относительно невысокой тактовой частоте.

Все команды можно классифицировать на 5 типов:
1. арифметические команды;
2. логические команды;
3. команды перехода;

· команды передачи данных;

· побитовые команды и команды тестирования битов.

Директивы ассемблера

Ассемблер поддерживает множество директив. Директивы не транслируются непосредственно в коды операции. Напротив, они используются, чтобы корректировать местоположение программы в памяти, определять макрокоманды, инициализировать память и так далее. То есть это указания самому ассемблеру, а не команды микроконтроллера.
Все директивы ассемблера приведены в табл. 1.2.

Таблица 1.2.
Директивы ассемблера

Директива Описание
BYTE Зарезервировать байт под переменную
CSEG Сегмент кодов
DB Задать постоянным(и) байт(ы) в памяти
DEF Задать символическое имя регистру
DEVICE Задать для какого типа микроконтроллера компилировать
DSEG Сегмент данных
DW Задать постоянное(ые) слово(а) в памяти
EQU Установите символ равный выражению
ESEG Сегмент EEPROM
EXIT Выход из файла
INCLUDE Включить исходный код из другого файла
LIST Включить генерацию .lst — файла
NOLIST Выключить генерацию .lst — файла
ORG Начальный адрес программы
SET Установите символ равный выражению

Синтаксис всех директив следующий:
.[директива]
То есть перед директивой должна стоять точка. Иначе ассемблер воспринимает это как метку.
Дадим несколько пояснений наиболее важным директивам ассемблера

CSEG — Code segment

Директива CSEG указывает на начало сегмента кодов. Ассемблируемый файл может иметь несколько кодовых сегментов, которые будут объединены в один при ассемблировании.
Синтаксис:

.CSEG
Пример:
.DSEG ; Начало сегмента данных
vartab: .BYTE 4 ; Резервируется 4 байта в СОЗУ
.CSEG ; Начало сегмента кодов
const: .DW 2 ; Записать 0x0002 в программной памяти
mov r1,r0 ; Что-то делать

DSEG — Data Segment

Директива DSEG указывает на начало сегмента данных. Ассемблируемый файл может содержать несколько сегментов данных, которые потом будут собраны в один при ассемблировании. Обычно сегмент данных состоит лишь из директив BYTE и меток.

.DSEG
Пример:
.DSEG ; Начало сегмента данных
var1: .BYTE 1 ; Резервировать 1 байт под переменную var1
table: .BYTE tab_size ; Резервировать tab_size байтов.
.CSEG
ldi r30,low(var1)
ldi r31,high(var1)
ld r1,Z

ESEG — EEPROM Segment

Директива ESEG указывает на начало сегмента EEPROM памяти. Ассемблируемый файл может содержать несколько EEPROM сегментов, которые будут собраны в один сегмент при ассемблировании. Обычно сегмент EEPROM состоит из DB и DW директив (и меток). Сегмент EEPROM памяти имеет свой собственный счетчик. Директива ORG может использоваться для размещения переменных в нужной области EEPROM.
Синтаксис:

.DSEG ; Начало сегмента данных
var1: .BYTE 1 ; Резервировать 1 байт под переменную var1
table: .BYTE tab_size ; Зарезервировать tab_size байт.
.ESEG
eevar1: .DW 0xffff ; Записать 1 слово в EEPROM

Написание программы

Текст программы можно набирать в любом текстовом редакторе, такие как встроенный редактор Norton Commander, FAR, а также Microsoft Word, WordPad и других. Также можно использовать специально предназначенные для этого программы Wavrasm, AVR Studio
Для создания программы не обязательно использовать ассемблер, программное обеспечение AVR поддерживает также и язык C или С++. Но в лабораторном комплексе этот вариант не рассматривается.
Программа, написанная на ассемблере, должна иметь определенную структуру.
Предлагается следующий шаблон (для AT90S8535)

;*******************************************
; название программы,
; краткое описание, необходимые пояснения
:*******************************************
;******подключаемые дополнительные файлы
.include “8535def.inc” ; файл описания AT90S8535
.include «имя_файла1.расширение» ; включение дополнительных
.include «имя_файла2.расширение» ; файлов
;******глобальные константы
.equ имя1 = xxxx ;
.equ имя2 = nnnn
;******глобальные регистровые переменные
.def имя1= регистр
.def имя2= регистр
;*******сегмент данных
.dseg
.org xxxx ; адрес первого зарезервированного байта
label1: .BYTE 1 ; резервировать 1 байт под переменную label1
label2: .BYTE m ; резервировать m байт под переменную label2
;****** сегментEEPROM(ЭСППЗУ)
.eseg
.org xxxx ; адрес первого зарезервированного байта
.db выражение1,выражение2,… ; записать список байтов в EEPROM.
.dw выражение1,выражение2,… ; записать список слов в EEPROM.
;******сегмент кодов
.cseg
.org $0000 ; адрес начала программы в программной памяти
;****** вектора прерываний (если они используются)
rjmp reset ;прерывание по сбросу
.org $0002
rjmp INT0 ;обработчик прерывания IRQ0
.org $0004
rjmp INT1 ;обработчик прерывания IRQ1
.org adrINTx ;адрес следующего обработчика прерываний
rjmp INTx ;обработчик прерывания x
……. ;далее по порядку располагать обработчики остальных ;прерываний

;*******начало основной программы
main: xxxx
… …

;******* подпрограммы
;*******подпрограмма 1
subr1: xxxx
…… ………. ……
ret
;*******подпрограмма 2
subr2: xxxx
…… ………. ……
ret
…………….
;******* программы обработчиков прерываний
INT0: xxxx
…… ………. ……
reti
INT1: xxxx
…… ………. ……
reti
INTx: xxxx
…… ………. ……
reti
………………………
; конец программы никак не обозначается.

Ниже приводятся 3 программы решения одной и той же простейшей программы, демонстрирующие использование директив ассемблера.

Как уже указывалось, программа простейшая: вычесть из числа 5 число 3. Если включен тумблер SA1 (рис. 1.2), то на индикацию выдать результат вычитания. Если тумблер SA1отключен – на индикацию вывести цифру ноль.
Алгоритм программы (рис. 1.5) соответствует программе №1, использующей директиву equ ассемблера.
Программа №2 отличается от программы №1 резервированием по одному байту оперативной памяти под семисегментные коды цифр от 0 до 9.

Программа №3 самая короткая. Она использует директиву .dw для определения слов в программной памяти. В программе используется команда LPM ассемблера. По этой команде загружается байт, адресуемый регистром Z в регистр R0. Команда обеспечивает доступ к любому байту памяти программы, организованной как 16 битное слово. Младший бит регистра Z определяет, осуществляется ли доступ к младшему байту слова (0) или к старшему (1).

Рис. 1.5 Алгоритм программы №1

;Программа №1.Использование директивы equ

.include «8535def.inc» ;включить файл – описание для AT90S8535
.dseg ;сегмент данных
.equ cod0=$64 ;присвоение имен ячейкам SRAM
.equ cod1=$65
.equ cod2=$66
.equ cod3=$67
.equ cod4=$68
.equ cod5=$69
.equ cod6=$6a
.equ cod7=$6b
.equ cod8=$6c
.equ cod9=$6d

.cseg
.org 0
rjmp reset
.org $30 ;начало программы

reset:
ldi r16,$00 ;определение стека с вершиной по адресу $00ff
out sph,r16
ldi r16,$ff
out spl,r16

ldi zl,$64 ;задание адреса начала зарезервированных ячеек
ldi zh,$00

ldi r16,$ff ;настроить порт С на выход
out ddrc,r16
ldi r16,00 ;настроить порт А на вход
out ddra,r16
ldi r16,$c ;настроить порт В: биты 2 и 3 на выход, остальные на вход
out ddrb,r16
ldi r16,$f0 ;настроить порт D: биты 0. 4 на вход, остальные на выход
out ddrd,r16

sbi portB,3 ;выдать 1 на разряд 3 порта В

ldi r17,$3f ;задание семисегментных кодов
sts cod0,r17
ldi r17,$06
sts cod1,r17
ldi r17,$5b
sts cod2,r17
ldi r17,$4f
sts cod3,r17
ldi r17,$66
sts cod4,r17
ldi r17,$6d
sts cod5,r17
ldi r17,$7d
sts cod6,r17
ldi r17,$07
sts cod7,r17
ldi r17,$7f
sts cod8,r17
ldi r17,$6f
sts cod9,r17

ldi r17,5 ;задание уменьшаемого
ldi r18,3 ;задание вычитаемого

m1: sbis pina,4 ;если включен тумблер SA1,то пропустить
rjmp m2 ;следующую команду

mov r20,r17 ; в r20 поместить уменьшаемое
sub r20,r18 ; вычесть вычитаемое
rjmp vv
m2:
ldi r20,0
vv:
push zl ;сохранить zl в стеке
add zl,r20 ;сложить zl с результатом
ld r0,z ;семисегментный код результата переслать в r20
pop zl ;извлечь zl из стека
out portc,r0 ;выдать результат на индикацию
rjmp m1

;Программа №2. Использование оперативной памяти под переменные

.include «8535def.inc» ;подключение файла описания AT90S8535

.dseg ;сегмент данных
.org $64 ;адрес первого зарезервированного байта
cod0:.byte 1 ;резервирование по одному байту под переменные
cod1:.byte 1
cod2:.byte 1
cod3:.byte 1
cod4:.byte 1
cod5:.byte 1
cod6:.byte 1
cod7:.byte 1
cod8:.byte 1
cod9:.byte 1

.cseg ;сегмент кодов
.org $0 ;адрес начала программы в программной памяти
rjmp reset ;прерывание по сбросу при подаче питания
;или при нажатии на кнопку «Сброс»
reset:
ldi r16,$00 ;определение стека с вершиной по адресу $00ff
out sph,r16
ldi r16,$ff
out spl,r16

ldi zl,$64 ;задание адреса начала зарезервированных ячеек
ldi zh,$00

ldi r16,$ff ;настроить порт С на выход
out ddrc,r16
ldi r16,00 ;настроить порт А на вход
out ddra,r16
ldi r16,$c ;настроить порт В: биты 2 и 3 на выход, остальные на вход
out ddrb,r16
ldi r16,$f0 ;настроить порт D: биты 0. 4 на вход, остальные на выход
out ddrd,r16

sbi portb,3 ;выдать 1 на разряд 3 порта В

ldi r17,$3f ;задание семисегментных кодов
sts cod0,r17
ldi r17,$06
sts cod1,r17
ldi r17,$5b
sts cod2,r17
ldi r17,$4f
sts cod3,r17
ldi r17,$66
sts cod4,r17
ldi r17,$6d
sts cod5,r17
ldi r17,$7d
sts cod6,r17
ldi r17,$07
sts cod7,r17
ldi r17,$7f
sts cod8,r17
ldi r17,$6f
sts cod9,r17

ldi r17,5 ;задание уменьшаемого
ldi r18,3 ;задание вычитаемого

m1: sbis pina,4 ;если включен тумблер SA1,то пропустить
rjmp m2 ;следующую команду

mov r20,r17 ; в r20 поместить уменьшаемое
sub r20,r18 ; вычесть вычитаемое
rjmp vv
m2:
ldi r20,0
vv: push zl ;сохранить zl в стеке
add zl,r20 ;сложить zl с результатом
ld r0,z ;семисегментный код результата переслать в r20
pop zl ;извлечь zl из стека
out portc,r0 ;выдать результат на индикацию
rjmp m1

;Программа №3. Использование директивы .dw

.include «8535def.inc» ;подключение файла описания AT90S8535

.cseg
.org 0
rjmp reset
.dw $063f,$4f5b,$6d66,$077d,$6f7f,$7c77,$5e39,$7179 ;семисегментные коды
reset:
ldi r16,$00 ;определение стека с вершиной по адресу $00ff
out sph,r16
ldi r16,$ff
out spl,r16
ldi r16,$ff
out ddrc,r16 ;настроить порт С на выход
ldi r16,00
out ddra,r16 ;настроить порт А на вход
ldi r16,$c
out ddrb,r16 ;настроить порт В: биты 2 и 3 на выход, остальные на вход
ldi r16,$f0
out ddrd,r16 ;настроить порт D: биты 0. 4 на вход, остальные на выход

sbi portb,3 ;выдать 1 на разряд 3 порта В

ldi zl,02 ;установить адрес семисегментного кода нуля в регистр Z
ldi zh,00

ldi r17,5 ;задание уменьшаемого
ldi r18,3 ;задание вычитаемого

m1: sbis pina,4 ;если включен SA1, то пропустить следующую команду
rjmp m2
mov r20,r17 ;в r20 поместить уменьшаемое
sub r20,r18 ;вычесть вычитаемое
rjmp vv
m2:
ldi r20,0 ;присвоить результату значение нуль
vv: push zl ;сохранить zl в стеке
add zl,r20 ; сложить zl с результатом
lpm ;загружаем бит, адресуемый регистром Z, в регистр R0
pop zl ;извлечь zl из стека
out portc,r0 ;выдать результат на индикацию
rjmp m1

Ввод программы

Подготовленная программа вводится в ПЭВМ с рабочего места после включения комплекса в работу.
Включение комплекса, собранного по схеме рис.1, осуществляется включением составных частей ПЭВМ и нажатием кнопки включения на блоке питания комплекса БП. Номер рабочего места устанавливается переключателем внутри блока управления и должен совпадать с номером на блоке связи с ЭВМ.

Переключатель режима работы платы ЖКИ рабочего места необходимо поставить в положение “Программирование”. При нажатии на кнопку “Сброс” блока управления на ЖКИ появляется надпись “Место” с соответствующим номером. Этому номеру будет соответствовать окно на экране дисплея ПЭВМ.

Программное обеспечение располагается в каталоге STAND90, в котором есть два подкаталога SERVER и PK&MK. Программное обеспечение работает в среде WINDOWS. Программа SERVER запускается файлом server.bat, программа PK&MK – файлом Pk&mk.exe.
Сразу после запуска программы-сервера на экран выводится меню из трех пунктов: 1 – удалить старые файлы (например, оставшиеся после предыдущей работы), 2 – загрузить старые файлы (для продолжения работы с ними), 3 – любая другая клавиша (например, пробел или Esc) – не удалять и не загружать. После нажатия соответствующей клавиши на экране появляется восемь окон.
Пример содержимого экрана ПЭВМ во время работы программы представлен на рис. 1.6.

Каждое окно имеет надпись “Место” с номером рабочего места и область размером 4х16 знакомест, в которой отображается информация, выводимая на ЖКИ соответствующего рабочего места. Внизу экрана имеется строка, в которой описаны “горячие” клавиши – клавиши и сочетания клавиш, нажатия на которые вызывают определенные действия.

Из “горячих” клавиш студенту доступна только клавиша F6 (просмотр ошибок). Назначение “горячих” клавиш представлено в табл. 1.3.
Узлы набора программ рабочих мест имеют встроенный микроконтроллер AT89C51 для управления ЖКИ и клавиатурой. Микроконтроллер передает клавиатурные коды с рабочих мест в ПЭВМ и отображает принятые от ПЭВМ данные на ЖКИ.

Операнды в языке ассемблера

Операнд – объект, над которым выполняется машинная команда.

Операнды ассембле­ра описываются выражениями с числовыми и текстовыми константами, мет­ками и идентификаторами переменных с использованием знаков операций и некоторых зарезервированных слов.

Операнды могут комбинироваться с арифметическими, логическими, побитовы­ми и атрибутивными операторами для расчета некоторого значения или опреде­ления ячейки памяти, на которую будет воздействовать данная команда или ди­ректива.

Способы адресации операндов

Под способами адресации понимаются существующие способы задания адреса хранения операндов:

Операнд задается на микропрограммном уровне (операнд по умолчанию): в этом случае команда явно не содержит операнда, алгоритм выполнения команды использует некоторые объекты по умолчанию (регистры, признаки и т.д.).

Операнд задается в самой команде (непосредственный операнд): операнд является частью кода команды. Для хранения такого операнда в команде выделяется поле длиной до 32 бит. Непосредственный операнд может быть только вторым операндом (источником). Операнд-получатель может находиться либо в памяти, либо в регистре.

Операнд находится в одном из регистров (регистровый операнд): в коде команды указываются именами регистров. В качестве регистров могут использоваться:

  • 32-разрядные регистры ЕАХ, ЕВХ, ЕСХ, EDX, ESI, EDI, ESP, EBP;
  • 16-разрядные регистры АХ, ВХ, СХ, DX, SI, DI, SP, ВР;
  • 8-разрядные регистры АН, AL, BH, BL, CH, CL, DH, DL;
  • сегментные регистры CS, DS, ,SS, ES, FS, GS.
  • прямую адресацию;
  • косвенную адресацию.

Прямая адресация : эффективный адрес определяется непосредственно полем смещения машинной команды, которое может иметь размер 8, 16 или 32 бита.

Ассемблер заменяет sum на соответствующий адрес, хранящийся в сегменте данных (по умолчанию адресуется регистром ds ) и значение, хранящееся по адресу sum , помещает в регистр eax .

Косвенная адресация в свою очередь имеет следующие виды:

  • косвенная базовая (регистровая) адресация;
  • косвенная базовая (регистровая) адресация со смещением;
  • косвенная индексная адресация;
  • косвенная базовая индексная адресация.

Косвенная базовая (регистровая) адресация. При такой адресации эффективный адрес операнда может находиться в любом из регистров общего назначения, кроме sp/esp и bp/ebp (это специфические регистры для работы с сегментом стека). Синтаксически в команде этот режим адресации выражается заключением имени регистра в квадратные скобки [].

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

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

Косвенная индексная адресация. Для формирования эффективного адреса используется один из регистров общего назначения, но обладает возможностью масштабирования содержимого индексного регистра.

Значение эффективного адреса второго операнда вычисляется выражением mas+( esi *4) и представляет собой смещение относительно начала сегмента данных.

Наличие возможности масштабирования существенно помогает в решении проблемы индексации при условии, что размер элементов массива постоянен и составляет 1, 2, 4 или 8 байт.

Данный вид адресации также может использоваться со смещением.

Косвенная базовая индексная адресация. Эффективный адрес формируется как сумма содержимого двух регистров общего назначения: базового и индексного. В качестве этих регистров могут применяться любые регистры общего назначения, при этом часто используется масштабирование содержимого индексного регистра.

Эффективный адрес второго операнда формируется как esi+edx . Значение по этому адресу помещается в регистр eax.

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

Операндом является порт ввода-вывода.
Помимо адресного пространства оперативной памяти микропроцессор поддерживает адресное пространство ввода-вывода, которое используется для доступа к устройствам ввода-вывода. Объем адресного пространства ввода-вывода составляет 64 Кбайт. Для любого устройства компьютера в этом пространстве выделяются адреса. Конкретное значение адреса в пределах этого пространства называется портом ввода-вывода. Физически порту ввода-вывода соответствует аппаратный регистр (не путать с регистром микропроцессора), доступ к которому осуществляется с помощью специальных команд ассемблера in и out .

Регистры, адресуемые с помощью порта ввода-вывода, могут иметь разрядность 8, 16 или 32 бит, но для конкретного порта разрядность регистра фиксирована. В качестве источника информации или получателя применяются регистры-аккумуляторы eax , ax , al . Выбор регистра определяется разрядностью порта. Номер порта может задаваться непосредственным операндом в командах in и out или значением в регистре dx . Последний способ позволяет динамически определить номер порта в программе.

Счетчик адреса – специфический вид операнда. Он обозначается знаком $. Специфика этого операнда в том, что когда транслятор ассемблера встречает в исходной программе этот символ, он подставляет вместо него текущее значение счетчика адреса (регистр EIP ). Значение счетчика адреса представляет собой смещение текущей машин­ной команды относительно начала сегмента кода, адресуемого сегментным регистром CS . При обработке транслятором очередной команды ассемблера счетчик адреса увеличивается на длину сформированной машинной команды. Обработка директив ассемблера не вле­чет за собой изменения счетчика. В качестве примера использования в команде значения счетчика адреса можно привести следующий фрагмент:

При использовании подобного выражения для перехода нельзя забывать о длине самой команды, в которой это выражение используется, так как значение счетчика адреса соответствует смещению в сегменте кода данной, а не следующей за ней команды. В приведенном выше примере команда jmp занимает 2 байта. Длина этой и некоторых других команд может зависит от того, какие в ней используются операнды. Команда с регистровыми операндами будет короче команды, один из операндов которой расположен в памяти. В большинстве случаев эту информацию можно получить, зная формат машинной команды.

Структурные операнды используются для доступа к конкретному элементу сложного типа данных, называемого структурой.

Записи (аналогично структурному типу) используются для доступа к битовому полю некоторой записи. Для доступа к битовому полю записи используется директива RECORD .

Операторы в языке ассемблера

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

Приоритет Оператор
1 length, size, width, mask, ( ), [ ],
2 .
3 :
4 ptr, offset, seg, this
5 high, low
6 +, — (унарные)
7 *, /, mod, shl, shr
8 +, -, (бинарные)
9 eq, ne, lt, le, gt, ge
10 not
11 and
12 or, xor
13 short, type

Характеристика основных операторов.

Арифметические операторы . К ним относятся унарные операторы + и , бинарные + и , операторы умножения *, целочисленного деления /, получения остатка от деления mod. Например,

Операторы сдвига выполняют сдвиг выражения на указанное количество разрядов. Например,

Операторы сравнения (возвращают значение истина или ложь) предназначены для формирования логических выражений. Логическое значение истина соответствует логической единице, а ложь – логическому нулю. Логическая единица – значение бита равное 1, логический ноль – значение бита, равное 0.

Если значение size больше или равно 50, то результат в аl равен 1, в противном случае — 0. Команда cmp сравнивает значение аl с нулем и устанавливает соответствующие флаги в EFLAGS . Команда je на основе анализа этих флагов передает или не передает управление на метку m1 .

Назначение операторов сравнения приведено в таблице

Оператор Условие
eq ==
ne !=
lt
ge >=

Логические операторы выполняют над выражениями побитовые операции. Выражения должны быть константными. Например,

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

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

Оператор переопределения типа ptr применяется для переопределения или уточнения типа метки или переменной, определяемых выражением. Тип может принимать одно из следующих значений.

Тип Пояснение Назначение
byte 1 байт переменная
word 2 байта переменная
dword 4 байта переменная
qword 8 байт переменная
tword 10 байт переменная
near ближний указатель функция
far дальний указатель функция

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

Оператор переопределения сегмента : (двоеточие) вычисляет физический адрес относительно конкретно задаваемой сегментной составляющей, в качестве которой могут выступать:

  • имя сегментного регистра,
  • имя сегмента из соответствующей директивы SEGMENT
  • имя группы.

Для выборки на выполнение очередной команды микропроцессор анализирует содержимое сегментного регистра CS , в котором содержится физический адрес начала сегмента кода. Для получения адреса конкретной команды микропроцессор складывает промасштабированное (умноженное на 16) значение сегментного регистра CS с содержимым регистра EIP . Запись CS:EIP содержит адрес текущей выполняемой команды. Аналогично обрабатываются операнды в машинных командах.

Оператор именования типа структуры . (точка) также заставляет транслятор производить определенные вычисления, если встречается в выражении.

Оператор получения сегментной составляющей адреса выражения seg возвращает физический адрес сегмента для выражения, в качестве которого могут выступать метка, переменная, имя сегмента, имя группы или некоторое символическое имя.

Оператор получения смещения выражения offset позволяет получить значение смещения выражения в байтах относительно начала того сегмента, в котором выражение определено. Например,

Оператор определения длины массива length возвращает число элементов, определенных операндом dup . Если операнд dup отсутствует, то оператор length возвращает значение 1.Например,

Оператор type возвращает число байтов, соответствующее определению указанной переменной:

Оператор size возвращает произведение длины length и типа type и используется при ссылках на переменную с операндом dup .
Для предыдущего примера

Оператор short –модификация атрибута near в команде jmp, если переход не превышает границы +127 и -128 байт. Например,

В результате ассемблер сокращает машинный код операнда от двух до одного байта. Эта возможность оказывается полезной для коротких переходов вперед, так как в этом случае ассемблер не может сам определить расстояние до адреса перехода и резервирует два байта при отсутствии оператора short .

Assembler. Система команд. Синтаксис Intel

Читайте также:

  1. Aloha системасы
  2. Cудебник 1550 г. Общая характеристика, система и источники
  3. I. Понятие и система принципов организации и деятельности прокуратуры РФ.
  4. II. Бреттон-Вудська система (створена в 1944 р.)
  5. II. Финансовая система РФ.
  6. III .1 Транспортная система городов и регионов
  7. III. Система мероприятий по реализации Концепции
  8. KOI8-R стал фактически стандартом для русской кириллицы в 1990-х годах в юникс-подобных операционных системах и электронной почте.
  9. TRAKO — Система керування рахунками клієнтів
  10. Автоматизована інформаційно-бібліотечна система
  11. Автономная система

Команды передачи данных.

mov (move – передать переасать) – скопировать.

dst – destination куда, src – source откуда.

reg — register регистр reg8/reg16/reg32

mem – memory mem8/mem16/mem32

imm – immediately непосредственное значение = const которое записано в коде.

mov работает с любыми представлениями. Запрещены пересылки из памяти в память mov mem, mem – ЗАПРЕЩЕНО. Все остальное можно

регистры CRi DRi TRi только с помощью mov с другими регистрами они работать не будут

Когда один из операндов eAX\AX\AL то общая длина команды сокращается на 1 байт, mov становится однооперандный.

exchange – меняет местами содержание источника и конца.

На время своего выполнения блокирует системную шину материнской платы. Гарантирует что на момент его исполнения никто другой не сможет вмешается, за счет того что блокируется системная шина на материнской плате.

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

Проблему синхронизации придумал и решил Деекстор.

XLALT – безоперандная команда. В 1 байт.

(translate) заменяет содержимое аккумулятора AL на байт из 256 байтов таблицы адрес которого находится в BX

YY ß -> копируется в AL[XX(YY)]
/|\ XX \|/
ß BX

Преобразует текущее значение AL в значение из какой-то таблицы.

из источника на вершину стека

PUSH srk – уменьшает значение

POP dst – увеличивает значение, извлекает с текущей вершины стека и помещает его в destination

PUSHA – помещает в стек содержание всех регистров 16 битных в след порядке AX/CX/DX/BX/SP/BP/SI/DI

POPA – извлекает с вершины стека в соответствующем порядке и заполняет их значение в регистрах, значение SP теряется.

PUSHAD – для 32 битных регистров

PUSHF PUSHFD — Помещает значение флагов

POPF POPFD — извлекает значение и записывает в регистры флагов

Команды ввода вывода.

in acc, port Ввод из фиксированного порта

in acc, dx Ввод из переменного порта

команда in помещает в аккумулятор 1 байт из некоторого адреса

out port, acc перемещает 1 байт из аккумулятор в порт

out dx, acc либо 1 байт в порт по адресу расположенному в dx

Обмен с периферией возможен только по байту, за передачу отвечает только процессор.

Арифметические команды.

add dst, src //dst=dst+src

add – складывает значение источника с текущим значением назначения, сумма попадает в dst

В src можно помещать разные регистры.

adc dst,src //dst=dst+src+CF

Если перенос (3+9=12) то CF=1

inc dst // dst=dst+1

int — Увеличение на единицу

150d = 0096h = 0000 0000 1001 0110b

1111 1111 0110 1010b = FF6Ah = -150d

sub dst,src ; dst=dst-src

sbl dst,src ; dst=dst-src-CF

dec dst ; dst=dst-1

Ы inc, dec – на CF не влияют

cmp dst,src ; dst-src

cmp – команда сравнения, на результат не влияет, результат сравнения находится в регистре флагов.

Команды умножения.

mul src ; AL=src*AL

умножается и результат помещается в аккумулятор

mul src ; ext:acc=acc*src

Умножение знаковых чисел

imul src ; идентичен умножению знаковых чисел

imul reg,src ; умножение регистра общего назначения на источник, результат попадает в регистр, старшая половина при этом теряется. reg=src*reg

imul reg,src,imm ; reg=src*imm также старшая половина теряется.

Команды деления.

div src ; DX/AX = acc/src DX – остаток от деления

относится к командам мультипликативным

idiv src ; знаковое деление, 2-х 3-х операндных вариантов нет

Команды преобразования.

CBW src ; convert bait to word расширение (был 8 битным стал 16 битным)

CND src ; convert word to double word (был 16 стал 32 битынм)

CDQ src ; был 32 стал 64 битным

Эти команды копируют знаковый бит в старшие разряды

BCD — числа упакованные в байт.

Логические операции.

NOT – унарная операция, конвертирует только биты.

Логические операции воздействуют друг на друга в межразрядных соединениях.

NOT – при реализации основного кода

остальные – для инициализации и булевой логики (XOR ax,ax).

Команды сдвига.

Единообразно воздействуют на все виды регистров, операндов, они передают побитовый сдвиг право i+1, при сдвиге лево i-1 если сдвигаем на 1 бит.

Сдвиги различаются тем как мы работаем с теми битами которые выдвигаются из регистров.

циклические (то что выпало, идёт на свободное место)


Циклические через CF (длина операндов увеличивается на 1)

Логические(то что выпало игнорируется и на свободное место помещается 0)

Арифметические (знаковый бит «размножается»)

Логические сдвиги влево, вправо SHLD SHRD (Shift Left\Right Double)

SHLD dst, src, count

объединяются в один регистр и производится сдвиг

Команды передачи управления.

Вызов, возврат из подпрограмм, обработка прерываний.

короткий/ближний/дальний переход (short, near, far)

короткий переход от -127 до 128 байт

ближний переход от -32 до 32 мб

дальний переход от -2 до 2 гб

Условные переходы.

JXX проверяются значения флагов.

Команд очень много, могут проверяться комбинации флагов.

JA — проверяют комбинацию регистров CF=0 и ZF=0 – Если выше

JBE — CF=0 и ZF=0 – Если не ниже/не равно.

Термины Выше, Не ниже, для без знаковых чисел.

JAE – проверяют значение CF=0 – выше/равно

JNB — проверяют значение CF=0

JNC — проверяют значение CF=0

JB — проверяют значение CF=1 — Ниже

JNAE- проверяют значение CF=1

JC — проверяют значение CF=1

JBE – проверяют значение CF=1 и ZF=1 – Ниже/равно

JNA — проверяют значение CF=1 и ZF=1

JE — проверка значение ZF=1 — Равно

JZ — проверка значение ZF=1

JNZ – проверяет на ZF≠0 – не равно 0

LOOP imm – CX-1 и передача управления на некоторое смещение, однооперандная команда, еще параметром называется непосредственное назначение, где-то выше loop должна быть метка, до тех пор пока не 0 происходит передача управления.

LOOPE – генерируют один и тот же код.

LOOPZ – кроме CX проверяется значение ZF==1 (результат предыдущей операции не 0). Если CX!=0 и ZF==1 то передача управления.

LOOPNE \ LOOPNZ – отрицание, CX==0 и ZF!=1

Вызов и возврат из подпрограмм.

CALL imm – программист вводит название функции, компилятор преобразует в адрес.

Подпрограмма выполняет свою логику, возможно использует фактические параметры из стека. По окончании логики функция помещает результат.

RET – целочисленное в AX, вещественное FPU и чотатам.

Команда RET может быть безоперандной и однооперандной RET imm

RET извлекает с вершины стека адрес точки возврата возвращает управление в этот адрес и тогда очистку стека от фактических параметров должен произвести обвязочный код (СИ конвенция).

Если с операндом то смещение на чотатам байт и очищается стек (Паскаль конвенция).

interruptеры.
INT n

n – в команде int это номер в команде которых необходимо обработать, номер из таблицы векторов прерываний, в результате процессор запоминает текущее состояние, которое прерывается, чотатам.

Интераптеры изменяют IP и передача управление в другой сегмент кода. Команды безусловного перехода которые jump.

Обработка цепочек.

Если нам надо произвести одинаковые действие над двумя массивами то мы предполагаем наличие циклов, но наличие цикла это однозначно ветвление и сброс с конвейера. Цепочечные команды конвейер не сбрасывают, позволяют реализовать часть циклических операций в одной строке.

Изменяют SI DI либо вперед либо назад, сдвигают начало массива и конец массива в значении от индекса.

Загружает регистры CX SI DI, потом вызываем команду цепочек и в одной строке повторяем все телодвижения над массивами, конвейер при этом не сбрасывается.

REP – повторяет чотатам

REPE/REPZ — проверяется флаг ZF

MOVS dst, src ; передает значение из источника в назначение

MOVSB – работа с байтами

MOVSW – работа со словами

MOVSD – работа с двойными словами.

CMPS dst, src ;не разрушающее вычитание, изменяются флаги, операнды не трогаются

SCAS dst ;однооперандная, вычитает содержимое просматриваемого массива и аккумулятора acc, dst. На равенство значения в аккумуляторе или не равенство.

STOS dst ;загружает в цепочку назначение цепочку аккумулятора. dst ç acc

LODS dst; acc ç dst

INS — ввод цепочек в некоторый порт

OUTS – вывод цепочек в некоторый порт

CLC (clear larry flag)

CMC (complementary carry)

STC (set carry)
CLD (clear Direction)

STD (Set Direction)

CLT (Clear Interrupt)

STI (Set Interrupt)

IF (Interrupt flag)

NOP (No Operation) – занимает по времени 1 такт процессора и по длине занимает 1 байт.

Работа с Ассемблером – Язык низкого уровня можно делать все что угодно в большинстве случаев затраты себя не окупают.

Ассемблер язык платформа зависимый. Это ограничивает сферы применения ассемблера:

1) Оптимизация (в большинстве по скорости);

2) Драйвера к железу.

3) Взлом программ.

Оптимизация. Возможно, оптимизация по скорости и возможно возникают иногда задачи оптимизации по объему памяти.

Требование к оптимизированным программам:

1) Результат работы оптимизированной программы должен совпадать с результатом работы до оптимизации.

2) Прирост производительности. (Можно разворачивать циклы, можно убирать условные переходы это дает прирост производительности в проценты)

SIMD (Simple Instruction Multiple Data)

Если мы можем входной поток данных (на вычислении) одной командой обрабатывать не одну, а множество операндов, то тогда мы получаем множественный так процессора.

Профайлером вылавливается самая напряженная функция, далее она оптимизируется (переписывается на ассемблер), далее компилируется в dll.

Шаблон ассемблерной dll:

.586 ; разрешать не привилегированные команды процессора 586

.XMM ; разрешает регистры XMM

PUBLIC _nameF@xx ;имя экспортируемой функции

mov al, 1 ; точка входа в dll

;если много функций то добавляем произвольно кол-во функций

push ebp ;стандартный заголовок функции

END_start@12 ;точка выхода и dll

Рекомендуемый редактор к программированию Notepad++ (npp)

Компиляция текстового файла:

Меняем .txt на .asl

ml.exe – создает объектный файл из текстового файла.

Для получения dll используется link32.exe – он из объектного файла делает файлы exp.lib и .dll (*.lnk)

в [name].lnk находится:

nameF – название нашей функции без искажения.

Модно создавать файл .bat или .cmd в который напишем

d:\work\..\ml.exe /c /coff /Cp /D_MASM ИМЯ.asm

d:\link32.exe ИМЯ.obj @ИМЯ.lnk

Рекомендуется перед началом компиляции удалять предыдущие результаты компилирования. .dll .obj exp

Рекомендуется создавать dll в другом каталоге

После компиляции скопировать

copy *.dll Куда/то/там

_ — подчеркивание, само!

XX – количество в байтах параметром передано функции.

Рекомендуется узнать, сколько параметров мы передаем, и написать прототип функции на языке высокого уровня.

Сравнить скорость работы функции на чистом си и с использование ассемблера.

По номеру варианта выбираем задание ассемблером программы.

Сделать Сишный эквивалент ассемблерной функции.

MMX (multi media edition)

8 регистров MMX:

Мантиссэ – регистры с плавающей запятой. 8BYTE

Декларируется что за одну операцию сложения в соответствующих словах результатов: мы получаем прирост производительности на упакованных байтах в 8 раз, на 4WORD в 4 раза и т.д. на учетверенных словах прирост производительности возможен также.

Набор команд:

movq dst,src ;копирует 64 бита 1QWORD из источника в назначение один из операторов должен быть MMX

Упаковка со знаком насыщения:

PACKSSWB mmx,src ; слова в байты

приемник регистр MMX

WB – копирует 4 слова со знаком из приемника в 4 младших байта приемника и копирует 4 слова из источника в старшие 4 байта приемника.

При этом если значение слова превышает 127, то в байт записывается 127. +127 d=7F h

Если меньше чем -128 то записывается минимальная из возможных -128. -128d=80h

Эти операции называются операциями насыщения.

Упаковка знаковая с насыщением слова в байты

Упаковка знаковая с насыщением двойных слов в слова

PACKSSWB – копирует 4 слова со знаком из приемника в 4 младших байта приемника и копирует 4 слова со знаком из источника в 4 старших байта приемника.

Команда PACKSSDW – тоже самое только из двойных слов в слова.

Упаковка без знакового насыщения.

PACKUSWB mmx, src.

Упаковывает без знаковые с насыщением слова в байты.

если больше 255d=FFh если меньше 0=0

РАСПАКОВКА ЧЕГОТОТАМ ТАМ ЧОТО ТАМ. Самостоятельно

Дата добавления: 2014-01-04 ; Просмотров: 2598 ; Нарушение авторских прав? ;

Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет

Клуб программистов

Delphi programming

Подписаться на рассылку:

Assembler&Win32. Курс молодого бойца. Урок 8.

Команды ассемблера

Арифметические операции — ADD, SUB, MUL, DIV. Многие опкоды делают вычисления. Вы можете узнать многие из них по их названиям: add (addition — добавление), sub (substraction — вычитание), mul (multiply — умножение), div (divide — деление).

Опкод add имеет следующий синтаксис:

add приемник, источник

Выполняет вычисление: приемник = приемник + источник.

Имеются также другие формы:

приемник источник пример
регистр регистр add ecx, edx
регистр память add ecx, dword ptr [104h] / add ecx, [edx]
регистр значение add eax, 102
память значение add dword ptr [401231h], 80
память регистр add dword ptr [401231h], edx

Эта команда очень проста. Она добавляет значение источника к значение приемника и помещает результат в приемник. Другие математические команды:

sub приемник, источник (приемник = приемник — источник)
mul множимое, множитель (множимое = множимое * множитель)
div делитель (eax = eax / делитель, edx = остаток)

Поскольку регистры могут содержать только целочисленные значения (то есть числа, не, с плавающей запятой), результат деления разбит на частное и остаток. Теперь, в зависимости от размера источника, частное сохраняется в eax, а остаток в edx:

размер источника деление частное в. остаток в.
BYTE (8-bits) ax / делитель AL AH
WORD (16-bits) dx:ax* / делитель AX DX
DWORD (32-bits) edx:eax* / делитель EAX EDX

* = Например: если dx = 2030h, а ax = 0040h, dx: ax = 20300040h. Dx:ax — значение dword, где dx представляет старшее word, а ax — младшее. Edx:eax — значение quadword (64 бита), где старшее dword в edx и младшее в eax.

Источник операции деления может быть:

  1. 8-бит регистр (al, ah, cl. )
  2. 16-бит регистр (ax, dx, . )
  3. 32-бит регистр (eax, edx, ecx. )
  4. 8-бит значение из памяти (byte ptr [xxxx])
  5. 16-бит значение из памяти (word ptr [xxxx])
  6. 6a 32-бит значение памяти (dword ptr [xxxx])

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

Язык ассемблера. Особенности, макросы, формат операторов, псевдокоманды. Часть 1.

Язык, на котором написана исходная программа, называется вход­ным языком, а язык, на который она переводится для исполнения процессо­ром, — выходным языком. Процесс преобразования входного языка в выходной язык называется трансляцией. Так как процессоры способны выполнять програм­мы на машинном языке двоичных кодов, который не используется для програм­мирования, то необходима трансляция всех исходных программ. Известны два способа трансляции: компиляция и интерпретация.

При компиляции исходная программа сначала полностью переводится в экви­валентную программу на выходном языке, называемую объектной программой, а затем выполняется. Этот процесс реализуется с помощью специальной про­граммы, называемой компилятором. Компилятор, для которого входной язык яв­ляется символической формой представления машинного (выходного) языка дво­ичных кодов, называется ассемблером.

При интерпретации каждая строка текста исходной программы анализируется (интерпретируется) и указанная в ней команда сразу выполняется. Реализация такого способа возлагается на программу–интерпретатор. Интерпретация занима­ет длительное время. Для повышения ее эффективности вместо обработки каждой строки интерпретатор предварительно осуществляет преобразование всех ко­мандных строк в символы (

). Сформированная последовательность симво­лов используется для выполнения возложенных на исходную программу функций.

Рассматриваемый ниже язык ассемблера реализуется с помощью компиляции.

Основные особенности ассемблера:

● вместо двоичных кодов в языке используются символьные имена — мнемо­ника. Например, для команды сложения (

и т. д. Символьные имена используются и для адресации ячеек памяти. Для программирования на языке ассемблера вместо двоичных кодов и адре­сов нужно знать только символические названия, которые ассемблер транс­лирует в двоичные коды;

● каждое высказывание соответствует одной машинной команде (коду), т. е. су­ществует взаимно однозначное соответствие между машинными командами и операторами в программе на языке ассемблера;

● язык обеспечивает доступ ко всем объектам и командам. Языки высокого уровня такой способностью не обладают. Например, язык ассемблера позво­ляет выполнить проверку бита регистра флагов, а язык высокого уровня (на­пример,

) такой способностью не обладает. Отметим, что языки для сис­темного программирования (например, С) часто занимают промежуточное положение. С точки зрения возможностей доступа они ближе к языку ассемб­лера, однако обладают синтаксисом языка высокого уровня;

● язык ассемблера не является универсальным языком. Для каждой определен­ной группы микропроцессоров имеется свой ассемблер. Языки высокого уровня лишены этого недостатка.

В отличие от языков высокого уровня написание и отладка программы на язы­ке ассемблера занимает много времени. Несмотря на это, язык ассемблера по­лучил широкое распространение в силу следующих обстоятельств:

● составленная на языке ассемблера программа имеет значительно меньшие размеры и работает гораздо быстрее, чем программа, написанная на языке высокого уровня. Для некоторых приложений эти показатели играют перво­степенную роль, например, многие системные программы (в том числе ком­пиляторы), программы в кредитных карточках, сотовых телефонах, драйверах устройств и др.;

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

В большинстве программ лишь небольшой процент всего кода отвечает за большой процент времени выполнения программы. Обычно 1% программы отве­чает за 50% времени выполнения, а 10% программы отвечает за 90% времени выполнения. Поэтому для написания конкретной программы в реальных ус­ловиях используется как ассемблер, так и один из языков высокого уровня.

Формат оператора в языке ассемблера.

Программа на языке ассемблера представляет собой список команд (высказываний, предложений), каждая из кото­рых занимает отдельную строку и содержит четыре поля: поле метки, поле опера­ции, поле операндов и поле комментариев. Для каждого поля отводится отдель­ная колонка.

Для поля метки отводится колонка 1. Метка является символи­ческим именем, или идентификатором, адреса памяти. Она необходима для того, чтобы можно было:

● совершить условный или безусловный переход к команде;

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

Такие высказывания снабжаются меткой. Для обозначения имени используют­ся (прописные) буквы английского алфавита и цифры. В начале имени должна стоять буква, в конце — разделитель в виде двоеточия. Метку с двоеточием мож­но писать на отдельной строке, а код операции — на следующей строке в колонке 2, что упрощает работу компилятора. Отсутствие двоеточия не поз­воляет отличить метку от кода операции, если они расположены на отдельных строках.

В некоторых версиях языка ассемблера двоеточия ставятся только после ме­ток команд, но не после меток данных, а длина метки может быть ограничена 6 или 8 символами.

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

Поле кода операции.

Это поле содержит мнемокод команды или псевдо­команды (см. ниже). Мнемокод команд выбирается разработчиками языка. В язы­ке ассемблера

для загрузки регистра из памяти выбрана мнемоника

), а для сохранения содержимого регистра в памяти — мнемоника

). В языках ассемблера

для обеих операций можно ис­пользовать одно имя, соответственно

. Если выбор названий мнемо­ник может быть произвольным, то необходимость использования двух машинных команд обусловлено архитектурой процессоров

Мнемоника регистров также зависит от версии ассемблера (табл. 5.2.1).

Здесь располагается дополнительная информация, необ­ходимая для выполнения операции. В поле операндов для команд перехода ука­зан адрес, куда нужно совершить переход, а также заданы адреса и регистры, ко­торые являются операндами для машинной команды. В качестве примера приве­дем операнды, которые могут быть использованы для 8–разрядных процессоров

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

— соответственно двоичная, восьмеричная, шестнадцатеричная, десятичная системы счисления (

можно не записывать). Если первой цифрой шестнадцатеричного числа являются А, В, С,

, то впереди добавляется незначащий 0 (нуль);

● коды внутренних регистров микропроцессора и ячейки памяти

М (источников или приемников информации) в виде букв А, В, С,

, М или их адреса в любой системе счисления (например, 10В — адрес регистра

в двоичной системе);

для регистровых пар ВС,

, Н; для пары аккумулятора и регистра признаков —

; для счетчика команд —

;для указателя стека —

● метки, указывающие адреса операндов или следующих команд в условных

(при выполнении условия) и безусловных переходах. Например, операнд М1 в команде

означает необходимость безусловного перехода к коман­де, адрес которой в поле метки отмечен идентификатором М1;

которые строятся путем связывания рассмотренных выше данных с помощью арифметических и логических операторов. Отметим, что способ резервирования пространства для данных зависит от версии языка. Разработчики языка ассемблера для

— определить слово), а позднее ввели альтернативный вариант .

который с самого начала был в языке для процессоров

Процессоры обрабатывают операнды разной длины. Для ее определения раз­работчики ассемблера приняли разные решения, например:

II регистры разной длины имеют разные названия: ЕАХ — для раз­мещения 32–битных операндов (тип

); АХ — для 16–битных (тип

и АН — для 8–битных (тип

к каждому коду операции прибавляются суффиксы: суффикс

; суффикс «.В» для типа

для операндов разной длины используются разные коды операций, например, для загрузки байта, полуслова (

) и слова в 64–битный ре­гистр используются коды операций

В этом поле приводятся пояснения о действиях про­граммы. Комментарии не влияют на работу программы и предназначены человеку. Они могут понадобиться для модификации программы, которая без таких ком­ментариев может быть совершенно непонятна даже опытным программистам. Комментарий начинается с символа и используется для пояснения и документи­рования программ. Начальным символом комментария могут служить:

● точка с запятой (;) в языках для процессоров фирмы

● восклицательный знак (!) в языках для

Каждая отдельная строка, отведенная под комментарий, предваряется начальным символом.

В языке ассемблера можно выделить два ос­новных вида команд:

базовые команды, являющиеся эквивалентом машинного кода процессора. Эти команды выполняют всю предусмотренную программой обработку;

псевдокоманды, или директивы, предназначенные для обслуживания процес­са трансляции программы на язык кодовых комбинаций. В качестве примера в табл. 5.2.2 приведены некоторые псевдокоманды из ас­семблера

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

● писать нужную последовательность команд всякий раз, когда она встречается. Такой подход приводит к увеличению объема программы;

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

Наиболее простой и эффективный способ многократного повторения цепочки команд состоит в использовании макроса, который можно представить как псевдо­команду, предназначенную для повторной трансляции часто встречающейся в про­грамме группы команд.

Макрос, или макрокоманда, характеризуется тремя аспектами: макроопреде­лением, макрообращением и макрорасширением.

— это обозначение многократно повторяемой последова­тельности команд программы, используемое для ссылок в тексте программы.

Макроопределение имеет следующую структуру:

Список выражений ; Макроопределение

В приведенной структуре макроопределения можно выделить три части:

макроса, включающий в себя имя

и набор параметров;

● отмеченное точками тело макроса;

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

Для повторного ассемблирования выбранной группы команд используется об­ращение, состоящее из имени

макрокоманды и перечня параметров с дру­гими значениями.

Когда в процессе компиляции ассемблер встречает макроопределение, он со­храняет его в таблице макроопределений. При последующих появлениях в про­грамме имени (

) макроса ассемблер замещает его телом макроса.

Использование имени макроса в качестве кода операции называется макро–обращением (макровызовом), а его замещение телом макроса — макрорасши­рением.

Если программу представить как последовательность символов (букв, цифр, пробелов, знаков пунктуации и возврата каретки для перехода на новую строку), то макрорасширение состоит в замене одних цепочек из этой последовательно­сти другими цепочками.

Макрорасширение происходит во время процесса ассемблирования, а не во время выполнения программы. Способы манипулирования цепочками символов возлагается на макросредства.

Процесс ассемблирования осуществляется в два прохода:

● на первом проходе сохраняются все макроопределения, а макровызовы расширяются. При этом исходная программа считывается и преобразуется в программу, в которой удалены все макроопределения, а каждый макро­вызов замещен телом макроса;

● на втором проходе обрабатывается полученная программа без макросов.

Макросы с параметрами.

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

● с фактическими параметрами, которые помещаются в поле операндов макро-обращения;


● с формальными параметрами. В процессе расширения макроса каждый фор­мальный параметр, появляющийся в теле макроса, замещается соответству­ющим фактическим параметром.

использования макросов с параметрами.

В программе 1 приведено две похожих последовательности команд, отличающихся тем, что пер­вая из них меняет местами Р и

В программе 2 включен макрос с двумя формальными параметрами Р1 и Р2. Во время расшире­ния макроса каждый символ Р1 внутри тела макроса замещается первым фактическим параметром (Р,

), а символ Р2 замещается вторым фактическим параметром (

) из программы № 1. В макровызо­ве

программы 2 обозначено: Р,

— первый фактический параметр,

— второй фактический параметр.

MOV EBX,Q MOV EAX,Pl

MOV Q,EAX MOV EBX,P2

MOV P,EBX MOV P2,EAX

Рассмотрим некоторые расширенные возмож­ности языка

Если макрос, содержащий команду условного перехода и метку, к которой со­вершается переход, вызывается два и более раз, то метка будет дублироваться (проблема дублирование меток), что вызовет ошибку. Поэтому при каждом вызове в качестве параметра приписывается (программистом) отдельная метка. В языке

метка объявляется локальной (

) и благодаря расширенным возмож­ностям ассемблер автоматически порождает другую метку при каждом расширении макроса.

позволяет определять макросы внутри других макросов. Такая расширенная возможность весьма полезна в сочетании с условной компоновкой программы. Рассмотрим

IF WORDSIZE GT 16 M2 MACRO

Макрос М2 может быть определен в обеих частях оператора

. Однако опре­деление зависит от того, на каком процессоре ассемблируется программа: на 16–битном или на 32–битном. Если М1 не вызывается, то макрос М2 вообще не будет определен.

Еще одна расширенная возможность состоит в том, что макросы могут вызы­вать другие макросы, в том числе самих себя — рекурсивный вызов. В последнем случае, чтобы не получился бесконечный цикл, макрос должен передавать само­му себе параметр, который изменяется при каждом расширении, а также про­верять этот параметр и завершать рекурсию, когда параметр достигает определенного значения.

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

При использовании мак­росов ассемблер должен уметь выполнять две функции: сохранять макроопреде­ления и расширять макровызовы.

Все имена макросов хранятся в таб­лице. Каждое имя сопровождается указателем на соответствующий макрос, что­бы в случае необходимости его можно было вызвать. Одни ассемблеры имеют отдельную таблицу для имен макросов, другие — общую таблицу, в которой наря­ду с именами макросов находятся все машинные команды и директивы.

При встрече с макросом в процессе ассемблирования создается:

новый элемент таблицы с именем макроса, числом параметров и указателем на другую таблицу макроопределений, где будет храниться тело макроса;

● список формальных параметров.

Затем считывается и сохраняется в таблице макроопределений тело макроса, представляющее собой просто цепочку символов. Формальные параметры, встречающиеся в теле цикла, помечаются специальным символом.

Внутреннее представление макроса

из приведенного выше примера для программы 2 (стр. 244) имеет вид:

MOV EAX,&P1; MOV EBX,&P2; MOV &P2EAX;MOV &

где в качестве символа возврата каретки используется точка с запятой, а в каче­стве символа формального параметра — амперсант &.

Всякий раз, когда при ассемблировании встречается макроопределение, оно сохраняется в таблице макросов. При вызове макроса ассемблер временно приостанавливает чтение входных данных из вход­ного устройства и начинает считывать сохраненное тело макроса. Извлеченные из тела макроса формальные параметры замещаются фактическими параметра­ми и предоставляются вызовом. Амперсант & перед параметрами позволяет ас­семблеру распознать их.

Несмотря на то, что существует много версий ассемблера, процессы ассемб­лирования имеют общие черты и во многом сходны. Ниже рассматривается рабо­та двухпроходного ассемблера.

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

● транслировать его на машинный язык;

● перенести полученный машинный код в файл, а соответствующую часть лис­тинга — в другой файл;

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

Однако такой подход не является эффективным. Примером может служить так называемая проблема опережающей ссылки. Если первым оператором является переход к оператору Р, расположенному в самом конце программы, то ассемблер не может транслировать его. Он сначала должен определить адрес оператора Р, а для этого необходимо прочитать всю программу. Каждое полное прочтение исходной программы называется проходом. Покажем, как можно решить пробле­му опережающей ссылки с использованием двух проходов:

● на первом проходе следует собрать и сохранить в таблице все определения символов (в том числе меток), а на втором проходе — выполнить чтение и ас­семблирование каждого оператора. Такой способ относительно прост, однако второй проход по исходной программе требует дополнительных временных затрат на операции ввода–вывода;

● на первом проходе следует преобразовать программу в промежуточную фор­му и сохранить ее в таблице, а второй проход выполнить не по исходной про­грамме, а по таблице. Такой способ ассемблирования позволяет сэкономить время, так как на втором проходе не выполняются операции ввода–вывода.

Для вывода листинга нужно сохранить полностью исходное выражение, вклю­чая комментарии. Если листинг не нужен, то промежуточную форму можно сократить, оставив только одни команды.

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

Цель первого прохода — построить таблицу символов. Как отмечалось выше, еще одной задачей первого прохода является сохранение всех макроопределений и расширение вызовов по мере их появления. Следовательно, в одном проходе происходит и определение символов, и расширение макросов. Символом может быть либо метка, либо значение, которому с помощью директи­вы приписывается определенное имя:

;Значение — размер буфера

Придавая значения символьным именам в поле метки команд, ассемблер по сути дела задает адреса, которые будет иметь каждая команда во время выпол­нения программы. Для этого ассемблер во время процесса ассемблирования со­храняет счетчик адреса команд (

) как специаль­ную переменную. В начале первого прохода значение специальной переменной устанавливается на 0 и увеличивается после каждой обработанной команды на длину этой команды. В качестве примера в табл. 5.2.3 приведен фрагмент про­граммы с указанием длины команд и значений счетчика. При первом проходе формируются таблицы символьных имен, директив и кодов операций, а при необ­ходимости литеральная таблица. Литерал — это константа, для которой ассемб­лер автоматически резервирует память. Сразу же отметим, что современные процессоры содержат команды с непосредственными адресами, поэтому их ас­семблеры не поддерживают литералы.

Таблица символьных имен

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

● длину поля данных, связанного с символом;

● биты перераспределения памяти (которые показывают, изменяется ли зна­чение символа, если программа загружается не в том адресе, в котором предполагал ассемблер);

● сведения о том, можно ли получить доступ к символу извне процедуры.

Символьные имена являются метками. Они могут быть заданы с помощью операторов (например,

В этой таблице приводятся все директивы, или псевдо­команды, которые встречаются при ассемблировании программы.

Таблица кодов операций.

Для каждого кода операции в таблице преду­смотрены отдельные графы: обозначение кода операции, операнд 1, операнд 2, 16–ричное значение кода операции, длина команды и тип команды (табл. 5.2.5). Коды операций делятся на группы в зависимости от числа и вида операндов. Тип команды определяет номер группы и задает процедуру, которая вызывается для обработки всех команд данной группы.

Цель второго прохода — создание объектной программы и распечатка при необходимости протокола ассемблирования; вывод информации, необходимой компоновщику для связывания процедур, которые ассемблирова­лись в разное время, в один выполняемый файл.

При втором проходе (как и при первом) строки, содержащие операторы, считываются и обрабатываются одна за другой. Исходный оператор и полученный из него в шестнадцатеричной системе выходной объектный код можно напечатать или поместить в буфер для последующей распечатки. После переустановки счет­чика адреса команды вызывается следующий оператор.

Исходная программа может содержать ошибки, например:

● приведенный символ не определен или определен более одного раза;

● код операции представлен недопустимым именем (из–за опечатки), не снабжен достаточным количеством операндов или имеет слишком много операндов;

Некоторые ассемблеры могут выявить неопределенный символ и заменить его. Однако в большинстве случаев при обнаружении оператора с ошибкой ассемблер выводит сообщение об ошибке на экран и пытается продолжить процесс ассемб­лирования.

Вторая частьстатьи посвященной языку ассемблер.

Арифметические команды Ассемблера

Команды сложения — ADD, ADC

Команды ADD (add — сложить) и ADC (add with carry- сложить с переносом) могут складывать как 8-, так и 16-битовые операнды.

Команда ADD складывает содержимое операнда-источника и операнда-приемника и помещает результат в операнд-приемник.

Формат команды: ADD приемник, источник

В символической нотации ее действия можно описать следующим образом: приемник := приемник + источник (в приемник записывается сумма содержимого приемника и источника).

Команда ADC делает то же, что и команда ADD, но складывает не два, а три слагаемых: приемник, источник и флаг переноса.

Формат команды: ADC приемник, источник + CF

В символической нотации ее действия можно описать как:

приемник := приемник + источник + содержимое флага переноса.

Перенос при сложении двоичных чисел аналогичен переносу при сложении десятичных чисел в столбик. Когда ЭВМ складывает двоичные числа и сумма не помещается в операнде-приемнике, то генерируется перенос. Как известно, 8-битовый регистр может содержать значения без знака в диапазоне от 0 до 255. Если мы, например, выполним двоичное сложение чисел 250 и 10, то получим следующий результат:

1111 1010; двоичное представление числа 250.

0000 1010; двоичное представление числа 10.

1 0000 0100; двоичное представление суммы, равной 260.

Результат верен, но занимает 9 двоичных битов. Если использовались 8 — битовые регистры, то младшие 8 битов будут занесены в регистр-приемник, а девятый бит- во флаг переноса CF.

Теперь понятно, почему микропроцессор 8086 имеет две разные команды сложения. Одна из них (ADD) может складывать значения, представляемые байтами или словами, а также младшие части значений повышенной точности. Другая команда (ADC) используется для сложения старших частей значений повышенной точности.

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

ADD АХ,MEM_WORD; прибавить содержимое ячейки памяти к регистру,

ADD MEM_WORD,AX; или наоборот, прибавить содержимое регистра к ячейки памяти.

ADD AL, 10; прибавить константу к содержимому регистра.

ADD MEM_BYTE,8H; сложить константу и содержимое ячейки памяти.

Допускается большинство возможных комбинаций, но нельзя складывать содержимое двух ячеек памяти или использовать в качестве приемника непосредственное значение (число).

Команды ADD и ADC могут воздействовать на следующие шесть флагов:

флаг переноса CF равен 1, если результат сложения не помещается в операн­де-приемнике, в противном случае он равен 0;

флаг четности PF равен 1, если результат имеет четное число битов со значением 1, в противном случае он равен 0;

вспомогательный флаг переноса AF равен 1, если результат сложения десятичных чисел требует коррекции;

флаг нуля ZF равен 1, если результат равен 0;

флаг знака SF равен 1, если результат отрицателен (старший бит равен 1), в противном случае он равен 0;

флаг переполнения OF равен 1, если слагаемое двух чисел одного знака превышает диапазон допустимых значений приемника в обратном коде, а сам приемник при этом меняет знак. Иначе флаг OF равен 0.

Команда увеличения значения приемника на единицу – INC

Команда INC(increment — прирастить) добавляет 1 к содержимому регистра или ячейки памяти, но в отличие от команды ADD не воздействует на флаг переноса CF. Формат команды: INC приемник.

Команда INC удобна для увеличения значений счетчиков в циклах команд. Ее можно использовать и для увеличения значения индексного регистра при доступе к последовательно расположенным ячейкам памяти. Операнд интерпретируется как число без знака.

INC CX; увеличить значение 16-битового

INC AL; или 8-битового регистра на единицу.

INC MEM_BYTE; увеличить значение байта

INC MEM_WORD; или слова памяти на единицу.

Не допускается использовать в качестве операнда непосредственное значение.

Команды вычитания — SUB, и вычитания с заемом SBB

Команды SUB (substract — вычесть) и SBB (substract with borrow — вычесть с заемом) аналогичны соответственно командам сложения ADD и ADC, только при вычитании флаг переноса CF действует как признак заема. Формат команды: SUB приемник,источник;

Команда SUB вычитает операнд -источник из операнда -приемника и помещает результат в приемник, в символической нотации:

приемник := приемник – источник.

Команда SBB делает то же самое, но дополнительно вычитает из приемника значение флага переноса CF:

SUB приемник,источник – СF;

Приемник := приемник — источник — содержимое флага переноса.

Как и в случае сложения, команды SUB и SBB выполняют две отдельные функции. Первая команда вычитает числа размером в байт или слово, а также младшие биты чисел повышенной точности (младшая часть числа расположена в регистре АХ, а старшая часть в регистре DX). Вторая команда вычитает старшие биты чисел повышенной точности. Например, команда SUB AX,CX; вычитает содержимое регистра СХ из содержимого регистра АХ и возвращает результат в регистр АХ.

Если размеры операндов превышают 16 бит, то необходимо применить следующую последовательность команд:

SUB АХ,CX; Вычесть младшие 16 бит;

SBB BX,DX; а затем старшие 16 бит.

Здесь мы вычитаем из 32-битового числа, помещенного в регистры АХ и ВХ, 32-битовое число, находящееся в регистрах СХ и DX. При вычитании содержимого регистра DX из содержимого регистра ВХ команда SBB учитывает возможность заема при выполнении первого вычитания.

Можно вычитать из содержимого регистра содержимое ячейки памяти (и наоборот) или вычитать из содержимого регистра либо ячейки памяти непосредственное значение. Примеры допустимых команд:

SUB АХ, MEM; Вычесть из регистра содержимое ячейки памяти.

SUB MEM [BX],AX; Вычесть из ячейки памяти регистр.

SUB AL,1O; Вычесть константу из регистра.

SUB MEM_BYTE,OFh; Вычесть константу из ячейки памяти.

Нельзя непосредственно вычесть содержимое одной ячейки памяти из другой или использовать непосредственное значение как приемник.

Команды SUB и SBB могут воздействовать на шесть флагов следующим образом:

· устанавливают флаг переноса CF в 1, если требуется заем, в противном случае он равен 0;

· устанавливают флаг четности PF в 1, если результат вычитания имеет четное число битов со значением 1, в противном случае он равен 0;

· устанавливают вспомогательный флаг переноса AF в 1, если результат вычитания десятичных чисел требует коррекции, в противном случае он равен 0;

· устанавливают флаг нуля ZF в 1, если результат равен 0, в противном случае он равен 0;

· устанавливают флаг знака SF в 1, если результат отрицателен (старший бит равен 1), в противном случае флаг равен 0;

· устанавливают флаг переполнения OF в 1, если при вычитании результат превышает диапазон значений приемника в обратном коде, а сам приемник изменяет знак.

Флаги SF и OF имеют смысл только при вычитании чисел со знаком, а флаг AF- только при вычитании десятичных чисел.

Команда уменьшения содержимого приемника — DEC

КомандаDEC приемник (decrement-уменьшить) вычитает 1 из содержимого регистра или ячейки памяти, но при этом (в отличие от команды SUB) не воздействует на флаг переноса CF.

Команда DEC часто используется в циклах для уменьшения значения счетчика до тех пор, пока оно не станет нулевым или отрицательным. Ее можно использовать также для уменьшения значения индексного регистра или указателя при доступе к последовательно расположенным ячейкам памяти. Например:

DEC CX; Уменьшить значение 16-битового,

DEC AL; или 8-битового регистра.

DEC MEM_BYTE; Уменьшить значение байтовой,

DEC MEM_WORD[BX]; или словной ячейки памяти.

Команды деления — DIV, IDIV

КомандаDIV (divide — разделить) выполняет деление чисел без знака, а команда IDIV (integer divide — разделить целые числа) выполняет деление чисел со знаком. Эти команды имеют формат:

DIV источник; где источник — делитель размером в байт или слово,

IDIV источник;находящийся в регистре общего назначения или в ячейке памяти.

Обратите внимание на следующее:

1. Делимое по отношению к делителю должно иметь двойной размер.

2. Делимое всегда должно находиться в регистре АХ (при делении на 8-битовое число) или в регистрах DX и АХ (при делении на 16-битовое число).

3. Результаты команды возвращаются следующим образом:

· если операнд-источник представляет собой байт, то частное возвращается в регистр AL, а остаток в регистр АН;

· если операнд-источник представляет собой слово, то частное возвращается в регистр АХ, а остаток — в регистр DX.

Обе команды оставляют состояние флагов неопределенными, но если частное не помещается в регистре-приемнике (AL или АХ), то микропроцессор генерирует прерывание типа 0 (деление на 0).

4. Переполнение результата деления возникает при следующих условиях:

· делитель равен 0;

· при делении байтов без знака делимое, по меньшей мере, в 256 раз превышает делитель;

· при делении слов без знака делимое, по меньшей мере, в 65 536 раз превышает делитель;

· при делении байтов со знаком частное лежит вне диапазона -128 до +127;

· при делении слов со знаком частное лежит вне диапазона от

Приведем несколько типичных примеров операций деления:

DIV BX; Разделить DX:AX на ВХ, без знака.

DIV MEM_BYTE; Разделить АХ на байт памяти, без знака.

IDIV DL; Разделить АХ на DL со знаком.

IDIV MEM WORD; Разделить DX:AX на слово памяти, со знаком.

Команды DIV и IDIV не позволяют прямо разделить на непосредственное значе­ние, так как процессор не может определить тип данных делителя.

Команды умножения — MUL, IMUL

Команда MUL (multiply-умножить) умножает числа без знака, a IMUL(integer multiply-умно­жить) умножает целые числа со знаком. Множимое и множитель у обеих команд должны быть данные одного типа, то есть байты, слова, двойные слова и т. д.

Эти команды имеют следующий формат:

MUL источник; гдеисточник — регистр общего назначения,

IMUL источник; или ячейка памяти размером в байт или слово.

В качестве первого операнда (множимого) команды MUL и IMUL используют содер­жимое регистра AL (при операциях над байтами) или регистра АХ (при операциях над словами). Произведение имеет двойной размер и возвращается следующим образом:

· умножение байтов -возвращает 16-битовое произведение в регистры АН (старший байт) и AL (младший байт);

· умножение слов -возвращает 32- битовое произведение в регистры DX (старшее слово) и АХ (младшее слово). Таким образом, размер произведения n— битных сомножителей равен 2n.

После исполнения команды MUL флаги CF и OF равны 0, если старшая половина произведения равна 0; в противном случае оба этих флага равны 1.

После исполнения команды IMUL флаги CF и OF равны 0, если старшая половина произведения представляет собой лишь расширение знака младшей половины. В противном случае они равны 1.

Несколько примеров умножения:

MUL BX; Умножить АХ на без ВХ знака.

MUL MEM_BYTE; Умножить содержимое ячейки памяти на AL.

IMUL DL; Умножить DL на AL со знаком.

IMUL MEM_WORD; Умножить ячейку памяти на АХ со знаком.

Команды MUL и IMUL не дозволяют в качестве операнда использовать непосредственное число.

Команды преобразования типов данных – CBW, CWD,CDQ

Существуют команды, позволяющие выполнять операции над смешанными данными за счет удвоения размера операнда со знаком.

Команда CBW (convert byte to wordпреобразовать байт в слово) копирует седьмой бит регистра AL во всех битах регистра АН.

Команда CWD (convert word to double word – преобразовать слово в двойное слово) копирует 15-й бит регистра АХ во всех битах регистра DX.

Команда CWDE копирует 15-й бит регистра АХ во всех битах регистра ЕАХ.

Команда CDQ – преобразовать двойное слово в учетверенное слово, копирует 31- й бит EAX во все битах EDX.

Таким образом, команда CBW позволяет сложить байт и слово, вычесть слово из байта и т.д. Аналогично команда CWD позволяет разделить слово на слово. Приведем несколько примеров:

CBW; Расширить AL до AX (байт до слова).

ADD AX,BX; Сложить байт в AL со словом в ВХ.

CBW; Расширить AL до AX.
IMUL ВХ; Умножить содержимое AL на содержимое ВХ.

CWD; Расширить AХ в DX (слово до двойного слова).

IDIV ВХ; Разделить слово в АХ на слово в ВХ.

Дата добавления: 2020-03-26 ; просмотров: 3952 | Нарушение авторских прав

Команды ассемблера

Представленная ниже страница, лишь часть огромного сайта посвященного различной компьютерной документации, на сайте собрано более 800 мб информации. Если Вы не нашли в этой статье, то что Вы ищите попробуте посмотреть здесь, cпросить на форуме или поискать необходимую Вам информацию в нашем каталоге ссылок сайтов компьтерной тематики.

Если же Вы хотите приобрести бумажную копию представленных здесь
материалов, обращайтесь в наш книжный магазин.

С уважением,
команда разработчиков eManual.ru

ЯЗЫК АССЕМБЛЕРА МИКРОПРОЦЕССОРА 8086

ЯЗЫК АССЕМБЛЕРА МИКРОПРОЦЕССОРА 8086

Язык ассемблера представляет собой машинный язык в символи­ческой форме, которая более понятна и удобна человеку.

Язык ассемблера микропроцессора Intel 8086 является довольно сложным, что в первую очередь объясняется сегментной организацией памяти и одновременной адресацией четырех сегментов. В языке имеется более 100 базовых символических команд, в соответствии с которыми ассемблер генерирует более 3800 машинных команд. Кроме того, в распоряжении программиста имеется более 20 директив, предназначенных для распределения памяти, инициализации перемен­ных, условного ассемблирования и т.д.

Исходная программа на языке ассемблера представляет собой последовательность операторов. Операторы обычно занимают одну строку. Ассемблер воспринимает операторы в свободном формате, т.е. элементам операторов не назначены фиксированные столбцы и между ними может быть любое число пробелов там, где это необходи­мо.

Операторы в исходной программе классифицируются как команд­ные операторы, операторы распределения данных и директивы ассемб­лера.

Командные операторы определяют генерируемые ассемблером ма­шинные команды; они содержат мнемонику и, при необходимости, один или два операнда. Каждый командный оператор порождает одну машин­ную команду, формат которой зависит от способа задания операндов.

Операторы распределения данных резервируют ячейки памяти для данных программы.

Директивы ассемблера содержат специальные указания для ассемблирующей программы и сами по себе не порождают никаких машинных кодов.

Формат командных операторов

Командные операторы записываются в следующем формате:

Метка: Префикс Мнемоника Операнд1,Операнд2 ;Комментарий

где фигурные скобки обозначают необязательные поля.

Рассмотрим назначение отдельных полей данного формата:

1) Метка представляет собой определяемое пользователем имя, заканчивающееся двоеточием. Значением метки является текущее значение счетчика ячеек (адресов) в текущем сегменте кода, т.е. адрес отмеченной команды. Метки как операнды используются только в командах передачи управления, и при этом двоеточие в конце ссылки на метку не ставится.

2) Префикс заставляет ассемблер сформировать один из префиксных байт — блокировки LOCK или повторения REP, который непосредствен­но предшествует команде.

3) Мнемоника кода операции представляет собой заранее опреде­ленное и неизменяемое имя, которое идентифицирует тип генерируе­мой машинной команды.

4) Операнды задают адреса данных или сами данные, необходимые в данной команде.

5) Комментарий предназначен только для документирования прог­раммы. Он всегда начинается с точки с запятой.

Формат директив ассемблера

и операторов распределения данных

Директивы ассемблера и операторы распределения данных имеют несколько иной формат:

Имя Директива Операнды ;Комментарий

Рассмотрим назначение отдельных полей данного формата:

1) Имя директивы, в отличие от метки, никогда не заканчивается двоеточием. Некоторые директивы требуют обязательного наличия метки.

2) Директива является одним из ключевых неизменяемых слов ассемблера и определяет его действия в процессе ассемблирования. Директивы используются программистом для распределения памяти, обеспечения связи между программными модулями и работы с символи­ческими именами.

3) Операнды конкретизируют действия, выполняемые по данной директиве.

4) Поле комментария аналогично такому же полю в командных опе­раторах.

Дадим определения основных терминов, которые будут использо­ваны в дальнейшем.

Ключевые (зарезервированные) слова представляют собой имена, имеющие для ассемблера строго определенный смысл. Их нельзя использовать в качестве идентификаторов.

Идентификатор как общий термин для меток и имен переменных — это определяемая программистом последовательность символов. Пер­вым символом в последовательности должна быть буква или один из символов @, подчеркивание или знак вопроса. В качестве последую­щих символов можно также использовать цифры. Максимальная длина идентификатора 31 символ.

Ассемблер процессора 8086 является жестко типизированным языком. Это означает, что операнды команд (регистры, переменные,

метки, константы) имеют связанный с ними атрибут типа, который

сообщает ассемблеру некоторую информацию об операнде. Атрибут

типа обычно подразумевается по умолчанию, но при необходимости

может быть задан явно.

8-разрядным регистрам AL, AH, BL, BH, CL, CH, DL, DH при­писан тип BYTE, а 16-разрядным регистрам AX, BX, CX, DX, BP, SP, SI, DI и сегментным регистрам CS, DS, SS, ES приписан тип WORD.

Разряды регистра флажков представляют собой однобитные ре­гисты, для установки и сброса каждого из которых используются отдельные машинные команды.

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

Переменная — это единица программных данных, имеющая симво­лическое имя.

Большинство ассемблерных программ начинается с определения данных, которыми они будут оперировать. Распределение ячеек памя­ти и присвоение им идентификаторов осуществляется с помощью директив DB (Define Byte — определить байт), DW (Define Word — определить слово), DD (Define Doubleword — определить двойное слово), DQ (Define Quadword — определить 4 слова) или DT (Define Tenbyte — определить 10 байтов).

Операторы распределения данных имеют следующий формат:

Имя DB нач.значение, нач.значение, .

Имя DW нач.значение, нач.значение, .

Имя DD нач.значение, нач.значение, .

Имя DQ нач.значение, нач.значение, .

Имя DT нач.значение, нач.значение, .

Таким образом, каждая директива может инициировать одну или несколько переменных соответствующего типа.


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

Например, оператор alpha DW 0Ah

резервирует слово памяти, присваивает ему идентификатор alpha и

заносит в него код 000A;

string DB ‘Привет’

резервирует 6 байт памяти и заносит в них строку символов и

присваивает этой строке идентификатор string.

Чтобы точно определить тип переменной, на которую произво­дится ссылка, ассемблер использует операторы BYTE PTR, WORD PTR и DWORD PTR (указатель на байт, слово и двойное слово соответствен­но).

Для инициализации массивов применяется конструкция DUP, которая в общем случае имеет вид:

n DUP (нач. значение, нач. значение, . )

где параметр n задает число повторений элементов, находящихся в

Например, оператор Addr DD 20 DUP (?)

резервирует место для 20 полных адресов и присваивает этому

массиву идентификатор Addr.

Метка представляет собой символическое имя для адреса ячейки памяти и предназначена для использования в качестве операнда в командах управления.

Константа — это численное значение, вычисляемое во время ассемблирования по заданному выражению.

Численные константы допускается представлять в системах счисления с основаниями 2, 8, 10 и 16. За младшей цифрой должен находиться однобуквенный дескриптор системы счисления: B — двоич­ная, O или Q — восьмеричная, D (необязательно) — десятичная, H-шестнадцатиричная. Шестнадцатиричная константа должна быть до­полнена слева незначащим нулем.

Символьная константа — это любой символ в коде ASCII. Символьная строка может содержать до 255 символов и должна быть заключена в одиночные кавычки.

СЕГМЕНТЫ И ПРОЦЕДУРЫ

Программы, написанные на языке ассемблера процессора 8086, могут быть разделены на один или несколько сегментов. Каждый логический сегмент имеет уникальное имя и однозначно отображается в сегментах памяти при загрузке программы для ее выполнения. Для определения начальной и конечной ячеек логического сегмента в макроассемблере предусмотрены директивы SEGMENT (начало сегмента) и ENDS (конец сегмента).

Обычно часть программы, содержащая коды машинных команд,

объединяется в кодовый сегмент. Переменные, константы, таблицы и

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

Директива ASSUME указывает ассемблеру, к какому сегментному регистру относится тот или иной логический сегмент. Если вся программа размещается в одном сегменте памяти, то эта директива указывает, что все сегментные регистры адресуют один и тот же сегмент.

В зависимости от используемой модели памяти в программе могут использоваться один или несколько сегментов кода и один или несколько сегментов данных. Стековый сегмент как правило один.

СТЕМА КОМАНД МИКРОПРОЦЕССОРА 8086

Систему команд процессора 8086 образуют 113 базовых команд, многие из которых допускают использование разнообразных режимов адресации.

По функциональному назначению выделяют спедующие группы ко­манд:

— команды передачи данных;

— команды арифметических операций;

— команды логических операций и сдвигов;

— команды передачи управления;

— команды управления микропроцессором.

КОМАНДЫ ПЕРЕДАЧИ ДАННЫХ

Команды передачи данных разделяют на 4 подгруппы:

— общие команды передачи данных;

— команды передачи цепочек байт или слов.

Команды передачи данных не модифицируют состояния флажков. Исключение составляют команды POPF и SAHF, прямо воздействующие на регистр флажков.

Далее будут использоваться следующие обозначения: dst — получатель,

mem — адрес памяти (смещение), заданный любым методом адресации,

reg — регистр общего назначения,

sreg — сегментный регистр,

aс — регистр-аккумулятор (AL или AX),

data — непосредственные данные.

ОБЩИЕ КОМАНДЫ ПЕРЕДАЧИ ДАННЫХ

В эту подгруппу входят команды, осуществляющие передачу регистр-регистр, регистр-память и память-регистр. Наиболее мощной среди них является команда MOV.

Эта команда имеет следующее обобщенное представление:

т.е. первым указывается операнд-получатель, а вторым — операнд­источник. Одним из операндов обязательно должен быть регистр.

Команда осуществляет передачу: регистр — регистр,

непосредственные данные — регистр,

непосредственные данные — память,

регистр — сегментный регистр,

память — сегментный регистр,

сегментный регистр — регистр,

сегментный регистр — память.

Допустимые форматы команды:

MOV mem/reg1, mem/reg2

MOV mem/reg, data

MOV sreg, mem/reg

MOV mem/reg, sreg

Команда обмена XCHG

Команда обмена XCHG позволяет обменивать содержимое любого общего регистра и ячейки памяти, а также любой пары общих регист­ров.

XCHG reg, mem/reg

Команда преобразования XLAT применяется для быстрого преоб­разования символов из одного кода в другой. Она заменяет содержи­мое аккумулятора AL на байт из 256-байтовой таблицы, начальный адрес которой находится в регистре BX, а восьмибитовое смещение — в регистре AL. В качестве сегментного используется регистр DS.

Команды LEA, LDS и LES

Команды LEA, LDS и LES предназначены для загрузки эффектив­ного адреса.

Команда LEA извлекает из памяти 16-битовый адрес и помещает его в один из общих регистров. Практически эта команда дублирует один из вариантов команды MOV, но выполняется быстрее.

Команда LDS извлекает из памяти 32-битовый адрес и помещает первое считанное из памяти слово в заданный общий регистр, а вто­рое — в сегментный регистр DS.

Команда LES извлекает из памяти 32-битовый адрес и помещает первое считанное из памяти слово в заданный общий регистр, а вто­рое — в сегментный регистр ES.

Обычно в команде LDS указывается регистр SI, а в команде LES регистр DI.

Команды LAHF и SAHF

Команда LAHF передает младший байт регистра флажков в регистр AH, а команда SAHF реализует обратную передачу — содержи­мое регистра AH передается в младший байт регистра флажков (стар­ший байт не изменяется).

Каждая команда занесения данных в стек PUSH имеет соот­ветствующую ей команду извлечения из стека POP. Для адресации вершины стека используется стековый указатель SP. Все стековые команды манипулируют только словами и сопровождаются автоматичес­кой модификацией указателя стека: при включении в стек произво­дится декремент, а при извлечении из стека — инкремент SP.

До выполнения стековых команд регистры SP и SS должны быть инициализированы.

Команда PUSH включает в стек содержимое адресуемого регистра или ячейки памяти, а команда POP извлекает содержимое вершины стека и передает его в регистр или ячейку памяти.

Команды POSHF и POPF предназначены для временного запомина­ния в стеке и последующего восстановления из стека содержимого регистра флагов. С их помощью можно изменять состояние флага трассировки TF, так как команд прямого воздействия на этот флаг нет.

PUSH mem/reg POP mem/reg

PUSH sreg POP sreg

Команда ввода IN и команда вывода OUT допускают работу как с байтами, так и со словами. Команда IN загружает данные из задан­ного порта в аккумулятор, а команда OUT выполняет передачу из аккумулятора в порт. Для портов ввода-вывода в диапазоне 00-FF можно использовать прямую укороченную адресацию, а остальные порты в диапазоне 100-FFFF можно адресовать только косвенно через регистр DX.

IN ac,port OUT port,ac (прямая укороченная адресация)

IN ac,DX OUT DX,ac (косвенная адресация)

КОМАНДЫ АРИФМЕТИЧЕСКИХ ОПЕРАЦИЙ

Процессор 8086 имеет широкий набор команд, реализующих арифметические операции, что позволяет применять его в сложных системах обработки данных.

Арифметические операции выполняются над целыми числами четы­рех типов: беззнаковыми двоичными, знаковыми двоичными, упакован­ными десятичными и неупакованными десятичными. Длина чисел может быть 8 или 16 бит.

Диапазоны чисел: беззнаковое 8-битное: 0 — 255, беззнаковое 16-битное: 0 — 65535, знаковое 8-битное: -128 — +127, знаковое 16-битное: -32768 — +32767.

Команды арифметических операций влияют на состояние флажков OF, SF, ZF, AF, PF и CF.

Одни и те же команды сложения и вычитания могут использо­ваться для операций как над беззнаковыми, так и знаковыми числа­ми. Контроль над типами чисел должен выполнять сам программист.

Команда ADD позволяет производить сложение 8- или 16-битовых двоичных чисел в режиме регистр-регистр, регистр-память и память­регистр, причем адресация памяти осуществляется в любом допусти­мом режиме. Общее представление команды имеет вид

т.е. первый операнд складывается со вторым и результат операции

замещает первый операнд.

Команда ADC выполняет сложение с переносом: в отличие от команды ADD в операции сложения участвует флажок CF, значение которого прибавляется к младшему биту результата сложения операн­дов.

Команда INC позволяет увеличить на 1 содержимое любого обще­го регистра или ячейки памяти.

Команда SUB позволяет производить вычитание 8- или 16-битных двоичных чисел. Общее представление команды имеет вид

т.е. второй операнд вычитается из первого и результат операции

замещает первый операнд.

Команда SBB выполняет вычитание с переносом: в отличие от команды SUB в операции вычитания участвует флажок CF, значение которого вычитается из младшего бита результата вычитания операн­дов.

Команда DEC позволяет уменьшить на 1 содержимое любого обще­го регистра или ячейки памяти.

Команда NEG изменяет знак числа, находящегося в регистре или ячейке памяти, на противоположный.

Команда сравнения CMP выполняет вычитание второго операнда из первого, но нигде не запоминает результат операции и влияет только на состояние флажков.

Микропроцессор 8086 имеет две команды умножения: для беззна­ковых и для знаковых двоичных чисел. Умножение десятичных чисел требует использования специальных команд коррекции, которые будут рассматриваться позднее.

Команда умножения беззнаковых целых чисел MUL выполняет умножение адресуемого операнда на содержимое аккумулятора. Общее представление команды имеет вид

При операции над байтами функции аккумулятора выполняет регистр AL, а 16-битный результат операции помещается в регистр AX. При операции над словами функции аккумулятора выполняет регистр AX, а произведение длиной 32 бита формируется в регистрах DX (старшее слово) и AX (младшее слово).

Команда IMUL аналогична команде MUL, но сомножители и произ­ведение интерпретируются как знаковые двоичные числа в дополни­тельном коде.

Микропроцессор 8086 имеет две команды деления: для беззнако­вых и для знаковых двоичных чисел. Деление десятичных чисел также требует использования специальных команд коррекции.

Команда деления беззнаковых чисел DIV производит деление содержимого аккумулятора и его расширения на содержимое адресуе­мого операнда.

При делении 16-битного делимого на 8-битный делитель делимое помещают в регистр AX. В результате выполнения операции частное формируется в регистре AL, а остаток — в AH.

При делении 32-битного делимого на 16-битный делитель стар­шая часть делимого помещается в регистр DX, а младшая — в AX. В результате выполнения операции частное формируется в регистре AX, а остаток — в DX.

При делении на 0 автоматически происходит прерывание и пере­ход к специальной программе обработки.

Команда IDIV аналогична команде DIV, но делимое, делитель и частное интерпретируются как знаковые двоичные числа в дополни­тельном коде.

Команда преобразования байта в слово CBW расширяет знак содержимого регистра AL в регистр AH. Команда преобразования сло­ва в двойное слово CWD передает знак содержимого регистра AX во все биты регистра DX.

Команды преобразования не влияют на состояния флагов.

КОМАНДЫ ДЕСЯТИЧНОЙ АРИФМЕТИКИ

Микропроцессор 8086 допускает два представления десятичных чисел: упакованный формат (BCD-формат) и неупакованный (ASCII- формат). В формате BCD байт содержит две десятичные цифры (по одной в каждой тетраде). В ASCII-формате байт содержит одну десятичную цифру в коде ASCII. В обоих форматах многоразрядные десятичные числа представляются последовательностями байт.

Команды десятичной арифметики оперируют только с байтами, причем основным рабочим регистром во всех десятичных операциях является регистр AL.

Операции с числами в форматах BCD и ASCII выполняются в два этапа: сначала над 8-битными операндами выполняются обычные операции двоичной арифметики, а затем осуществляется коррекция результата. Команды коррекции являются безадресными, так как работают с содержимым аккумулятора AL.

Команды для формата BCD

Команда десятичной коррекции для сложения DAA выполняет кор­рекцию суммы, полученной в результате выполнения команд ADD и ADC и должна следовать непосредственно за ними.

Команда десятичной коррекции для вычитания DAS выполняет коррекцию разности, полученной в результате выполнения команд SUB и SBB и должна следовать непосредственно за ними.

Команды для формата ASCII

Команда десятичной коррекции для сложения AAA выполняет кор­рекцию суммы, полученной в результате выполнения команд ADD и ADC и должна следовать непосредственно за ними.

Команда десятичной коррекции для вычитания AAS выполняет коррекцию разности, полученной в результате выполнения команд SUB и SBB и должна следовать непосредственно за ними.

Команда десятичной коррекции для умножения AAM выполняет кор­рекцию произведения, полученного в результате выполнения команды MUL и должна следовать непосредственно за ней. Старший разряд результата помещается в регистр AH, младший — в AL.

Команда десятичной коррекции для деления AAD отличается тем, что должна выполняться перед командой деления DIV.

КОМАНДЫ ЛОГИЧЕСКИХ ОПЕРАЦИЙ И КОМАНДЫ СДВИГОВ

КОМАНДЫ ЛОГИЧЕСКИХ ОПЕРАЦИЙ

Логические операции представлены командами NOT (инверсия), AND (конъюнкция), OR (дизъюнкция), XOR (исключающее ИЛИ) и коман­дой TEST, которая выполняет конъюнкцию операндов, но не изменяет их значений. Все логические операции являются поразрядными, т.е. выполняются независимо для всех бит операндов.

Бинарные команды AND, OR, XOR и TEST воздействуют на флажки OF, SF, ZF, PF и CF. Унарная операция NOT не влияет на состояние флажков.

Команды сдвигов подразделяются на команды простых сдвигов и команды циклических сдвигов. Циклические сдвиги влияют только на флаги OF и CF, а обычные изменяют пять флажков: OF, SF, ZF, PF и

CF. Команды сдвигов могут работать как с байтами, так и со слова­ми.

Команды ROL и ROR реализуют простой циклический сдвиг влево и вправо соответственно, помещая значение из выдвигаемого бита в освобождающийся бит.

Команды RCL и RCR называются командами циклического сдвига влево и вправо через перенос, так как флажок CF расширяет сдвига­емый операнд на один бит. Таким образом, значение из CF загружа­ется в освобождающийся бит, а выдвигаемый бит помещается в CF.

Команды SHL и SHR реализуют логический сдвиг влево и вправо соответственно. Для логического сдвига характерно, что в освобож­дающийся бит загружается нуль, а выдвигаемый бит теряется.

Команды SAL и SAR предназначены для арифметического сдвига влево и вправо. Арифметический сдвиг вправо отличается от логи­ческого сдвига тем, что знаковый бит не сдвигается, а дублируется в соседнем правом бите, сохраняя тем самым знак числа. Арифмети­ческий сдвиг влево эквивалентен логическому, поэтому мнемоники SAL и SHL обозначают одну и ту же машинную команду. Команды арифметического сдвига по существу реализуют умножение и деление чисел без знака на степень числа 2.

Поле операнда команд сдвига имеет вид mem/reg,count. Опреанд count определяет число сдвигов и может быть указан как констан­та 1 или как регистр CL. В первом случае выполняется сдвиг на один бит, а во втором число сдвигов определяется содержимым регистра CL, которое воспринимается как беззнаковое число.

ROL mem/reg,1 ROL mem/reg,CL

ROR mem/reg,1 ROR mem/reg,CL

RCL mem/reg,1 RCL mem/reg,CL

RCR mem/reg,1 RCR mem/reg,CL

SHL mem/reg,1 SHL mem/reg,CL

SHR mem/reg,1 SHR mem/reg,CL

SAL mem/reg,1 SAL mem/reg,CL

SAR mem/reg,1 SAR mem/reg,CL

КОМАНДЫ ПЕРЕДАЧИ УПРАВЛЕНИЯ

Сегментная организация программной памяти определяет две основные разновидности команд передачи управления. Передача управления в пределах текущего сегмента кода называется внутри­сегментной — при этом модифицируется только регистр IP и адрес перехода может быть представлен одним словом. Такая передача управления называется ближней (тип NEAR), а ее вариант с сокра­щеннным диапазоном адресов переходов — короткой. Передача управ­ления за пределы текущего сегмента кода называется межсегментной или дальней (тип FAR) — при этом необходимо модифицировать содер­жимое регистров IP и CS и адрес перехода представляется двумя словами (сегмент:смещение).

Команды передачи управления процессора 8086 подразделяются на команды безусловных переходов, условных переходов, вызовов, возвратов, управления циклами и команды прерываний.

Команды передачи управления не изменяет состояние регистра флагов (за исключением команды IRET).

КОМАНДЫ БЕЗУСЛОВНЫХ ПЕРЕХОДОВ

Команды безусловного перехода имеют общую мнемонику JMP. Команда короткого безусловного перехода содержит во втором байте смещение, которое интерпретируется как знаковое целое. Диапазон значений байта смещения составляет -128 — +127. Если смещение положительное, осуществляется переход вперед, а если отрицатель­ное — переход назад.

Команда ближнего безусловного перехода может либо непосред­ственно содержать 16-битное смещение, либо косвенный адрес 16-битного смещения. Диапазон смещения составляет -32768 — +32767 байт относительно адреса команды, находящейся после команды JMP.

Команда дальнего безусловного перехода реализует прямой и

косвенный межсегментнные переходы.

JMP dispL — короткий переход

JMP disp — ближний прямой переход

JMP mem/reg — ближний косвенный переход

JMP addr — дальний прямой переход

JMP mem — дальний косвенный переход

КОМАНДЫ УСЛОВНЫХ ПЕРЕХОДОВ

В системе команд процессора 8086 имеется 19 двухбайтных команд условных переходов. При выполнении этих команд анализиру­ется некоторое условие, закодированное текущими состояниями фла­гов, и если оно выполняется, то осуществляется переход, а если нет, то выполняется следующая по побядку команда.

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

Мнемонические обозначения команд:

1) Команды для работы с беззнаковыми числами: JA/JNBE — переход, если больше; JAE/JNB/JNC — переход, если больше или равно; JB/JNAE/JC — переход, если меньше; JBE/JNA — переход, если меньше или равно.

2) Команды для работы со знаковыми числами: JG/JNLE — переход, если больше; JGE/JNL — переход, если больше или равно; JL/JNGE — переход, если меньше; JLE/JNG — переход, если меньше или равно; JNS — переход, если больше нуля; JS — переход, если меньше нуля.

3) Команды, общие для знаковых и беззнаковых чисел: JE/JZ — переход, если равно / переход, если ноль; JNE/JNZ — переход, если не равно / переход, если не ноль;

JNO — переход, если нет переполнения;

JO — переход, по переполнению.

4) Прочие команды:

JCXZ — переход, если содержимое регистра CX равно нулю;

JNP/JPO — переход при отсутствии четности;

JP/JPE — переход по четности.

Форматы команд такие же, как у короткого безусловного пере­хода.

КОМАНДЫ ВЫЗОВОВА ПОДПРОГРАММ

Команда вызова подпрограммы CALL передает управление с авто­матическим сохранением адреса возврата в стеке. В поле операнда этой команды находится метка первой команды вызываемой подпрог-

При переходе к подпрограмме необходимо временно запомнить адрес команды, находящейся после команды CALL. Этот адрес называ­ется адресом возврата. После того, как подпрограмма закончит свои действия, завершающая ее команда возврата RET передает управление по запомненному адресу возврата. Адрес возврата запоминается в стеке.

Вызовы могут быть внутрисегментными (тип NEAR) или межсег­ментными (тип FAR). В первом случае вызываемая подпрограмма находится в текущем сегменте кода, а во втором — в произвольном.

Команды внутрисегментного перехода производят декремент SP на 2, включают в стек содержимое IP, а затем прибавляют к IP 16-битное смещение, которое интерпретируется как знаковое целое.

Команды межсегментного перехода производят декремент SP на 2, включают в стек содержимое CS, снова производят декремент SP на 2, включают в стек содержимое IP, затем в IP загружается значение смещения, а в CS — сегментный адрес.

CALL disp — непосредственный ближний вызов;

CALL mem/reg — косвенный ближний вызов;

CALL addr — непосредственный дальний вызов;

CALL mem — косвенный дальний вызов.

КОМАНДЫ ВОЗВРАТА ИЗ ПОДПРОГРАММ

Каждая подпрограмма должна содержать минимум одну команду возврата RET, которая возвращает управление вызывающей программе. Такая передача управления осуществляется путем извлечения из стека адреса возврата, включенного в него командой вызова под­программы.

Команды внутрисегментного и межсегментного возврата имеют одну и ту же мнемонику RET. Тип команды, соответствующей этой мнемонике, определяется ассемблером автоматически.

RET — однобайтный вариант,

RET data — трехбайтный вариант.

Однобайтная команда RET с кодом операции C3 реализует внут­рисегментный возврат. Она передает слово из вершины стека в IP и увеличивает SP на 2.

Однобайтная команда RET с кодом операции CB осуществляет межсегментный возврат. Она передает слово из вершины стека в IP, увеличивает SP на 2. передает слово из вершины стека в CS и снова увеличивает SP на 2.

Трехбайтные варианты команд возврата осуществляют те же действия, что и однобайтные, а затем прибавляют содержащиеся в них данные к указателю стека. Эти команды предназначены для упро­щения возврата из тех подпрограмм, параметры которых передаются в стеке. Прибавление к SP данных из RET эквивалентно удалению пара-

метров из стека.

КОМАНДЫ УПРАВЛЕНИЯ ЦИКЛАМИ

Три команды управления циклами применяются для организации программных циклов. В них предусматривается использование регист­ра CX в качестве счетчика цикла.

В поле операнда команд управления циклами находится метка первой команды цикла (8-битовое смещение). Диапазон переходов этих команд составляет -128 — +127 байт от следующей команды.

Команда LOOP производит декремент регистра CX и, если содер­жимое CX не равно нулю, происходит переход к началу цикла. В противном случае выполняется следующая по порядку команда.

Мнемоники LOOPE/LOOPZ определяют одну и ту же машинную команду, которая производит декремент регистра CX, а затем пере­дает управление в начало цикла, если содержимое CX не равно нулю и ZF=1. В противном случае выполняется следующая по порядку команда.

Мнемоники LOOPNE/LOOPNZ также определяют одну и ту же машин­ную команду, которая производит декремент регистра CX, а затем передает управление в начало цикла, если содержимое CX не равно нулю и ZF=0. В противном случае выполняется следующая по порядку команда.

В процессоре 8086 имеются 3 команды, относящиеся к прерыва­ниям.

Команда программного прерывания INT вызывает программу обра­ботки, определяемую типом прерывания.

INT type — вызов прерывания с номером type (от 0 до 255),

INT — вызов прерывания контрольного останова (номер 3).

Команда INT выполняется следующим образом:

1) декремент указателя стека на 2;

2) включение в стек содержимого регистра флажков;

3) сброс флажков IF и TF;

4) декремент указателя стека на 2;

5) включение в стек содержимого регистра CS;

6) определение адреса вектора прерывания ADDRESS путем умноже­ния кода типа прерывания на 4;

7) загрузка в регистр CS слова памяти, расположенного по адресу ADDRESS+2;

8) декремент указателя стека на 2;

9) включение в стек содержимого IP;

10) загрузка в регистр IP слова памяти, расположенного по адресу ADDRESS.

В результате этих действий осуществляется межсегментный кос-

венный вызов подпрограммы обработки прерывания.

Команда прерывания при переполнении INTO генерирует прог­раммное прерывание только в том случае, если установлен флаг переполнения. Она вызывает прерывание с номером 4.

Команда возврата из прерывания IRET предназначена для выхода из подпрограммы обработки прерываний, инициированной аппаратно или программно.

Команда IRET выполняется следующим образом:

1) слово из вершины стека передается в IP;

2) производится инкремент SP на 2;

3) слово из вершины стека передается в CS;

4) производится инкремент SP на 2;

5) слово из вершины стека передается в регистр флагов;

6) производится инкремент SP на 2.

Под цепочкой понимается последовательность любых контекстно связанных байт или слов, находящихся в смежных ячейках памяти.

В системе команд процессора 8086 имеется 5 команд, предназ­наченных для обработки одного элемента цепочки. Цепочечной команде может предшествовать специальный однобайтный префикс повторения REP, который вызывает повторение действия команды над следующими элементами цепочки. Повторение расчитано на максималь­ную длину цепочек 64 Кбайт и выполняется значительно быстрее цикла LOOP.

Цепочечные команды могут иметь операнд-источник, операнд­получатель или и то и другое одновременно. Подразумевается, что цепочка-источник по умолчанию находится в текущем сегменте дан­ных, но допускается префикс замены сегмента. Цепочка-получатель может находиться только в текущем дополнительном сегменте. При этом содержимое регистра SI всегда считается смещением текущего элемента цепочки-источника, а содержимое регистра DI — смещением текущего элемента цепочки-получателя.

Необходимые в команде индексные и сегментные регистры должны быть инициализированы до ее выполнения.

При выполнении цепочечной команды содержимое регистров SI и DI автоматически изменяется, чтобы адресовать следующие элементы цепочек. Флаг направления DF определяет автоинкремент (DF=0) или автодекремент индексных регистров.

Если команде предшествует префикс повторения, то после каждого ее выполнения производится декремент регистра-счетчика CX, поэтому его необходимо предварительно инициализировать на

требуемое число повторений. Когда содержимое CX достигает нуля,

управление передается следующей команде.

Префикс повторения имеет 5 мнемокодов: REP, REPE, REPZ, REPNE, REPNZ.

Префикс REP используется с командами MOVS и STOS и вызывает повторение операции до тех пор, пока содержимое CX не равно 0.

Префиксы REPE и REPZ соответствуют тому же коду команды, что и мнемоника REP, но используются совместно с командами CMPS и SCAS. Они вызывают повторение операции до тех пор, пока ZF=1 и содержимое CX не равно 0.

Префиксы REPNE и REPNZ соответствуют одному коду команды, и используются совместно с командами CMPS и SCAS. Они вызывают повторение операции до тех пор, пока ZF=0 и содержимое CX не рав­но 0.

Команда MOVS передает байт или слово из цепочки, адресуемой регистром SI, в цепочку, адресуемую регистром DI. Команда переда­чи цепочки байт MOVSB после пердачи байта увеличивает содержимое регистров SI и DI на 1, а команда передачи цепочки слов MOVSW после передачи слова увеличивает их содержимое на 2.

Команда сравнения цепочек CMPS производит вычитание байта или слово цепочки, адресуемой регистром DI, из байта или слова цепочки, адресуемой регистром SI. В зависимости от результата вычитания устанавливаются флаги, но сами операнды не изменяются. Команда сравнения цепочек байт CMPSB после каждой операции срав­нения увеличивает содержимое регистров SI и DI на 1, а команда сравнения цепочек слов CMPSW — на 2.

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

не изменяются. Команда сканирования цепочки байт SCASB после каж­дой операции сканирования увеличивает содержимое регистра DI на 1, а команда сканирования цепочки слов SCASW — на 2.

Команда загрузки цепочки в аккумулятор LODS загружает эле­менты цепочки, адресуемой регистром SI, в аккумулятор AL или AX. Команда загрузки цепочки байт LODSB после выполнения каждой опе­рации увеличивает содержимое регистра SI на 1, а команда загрузки цепочки слов LODSW — на 2.

Команда запоминания содержимого аккумулятора в цепочке STOS передает содержимое аккумулятора в элемент цепочки, адресуемый регистром DI. Команда запоманания цепочки байт STOSB после выпол­нения каждой операции увеличивает содержимое регистра DI на 1, а команда запоминания цепочки слов STOSW — на 2.

КОМАНДЫ УПРАВЛЕНИЯ МИКРОПРОЦЕССОРОМ

Команды данной группы обеспечивают программное управление различными функциями процессора. Они делятся на две подгруппы: команды установки флагов и команды синхронизации.

Илон Маск рекомендует:  tab-size в CSS
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL