Страница 1| Старница 2



Языки программирования

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

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

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

Языки высокого уровня - это языки программирования, позволяющие записывать программу в удобном для человека виде. Данные языки ориентированы не на систему команд того или иного процессора, а на систему операторов (команд), характерных для записи определенного класса алгоритмов.

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

BASIC (Beginner's All-purpose Symbolic Instruction Code) Рожденный в 60-е годы в Америке (столь любящей простые решения), Бейсик был задуман как простой язык для быстрого освоения. Бейсик стал фактическим стандартом для МикроЭВМ именно благодаря своей простоте как в освоении так и в реализации. Однако для достижения этого качества был принят ряд решений (отсутствие типизации, нумерация строк и неструктурное GOTO, и др.), негативно сказывающихся на стиле изучающих программирование. Кроме того, недостаток выразительных средств привел к появлению огромного количества диалектов языка, не совместимых между собой. Современные, специализированные версии Бейсика (такие как Visual Basic) несмотря на приобретенную "структурность" обладают все теми же недостатками, прежде всего - небрежностью по отношению к типам и описаниям. Пригоден для использования на начальном этапе обучения, как средство автоматизации (в случаях когда он встроен в соответствующие системы) либо как средство для быстрого создания приложений.

Pascal Разработанный известным теоретиком Н.Виртом на основе идей Алгола-68, Паскаль предназначался прежде всего для обучения программированию. Построенный по принципу "необходимо и достаточно", он располагает строгим контролем типов, конструкциями для описания произвольных структур данных, небольшим, но достаточным набором операторов структурного программирования. К сожалению, обратной стороной простоты и строгости является громоздкость описаний конструкций языка. Наиболее известная реализация - Turbo/Borland Pascal - несмотря на отличия от стандарта Паскаля, представляет из себя среду и набор библиотек, сделавшие из учебного языка промышленную систему для разработки программ в среде MS-DOS.

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

C и C++ В основе языка C - требования системного программиста: полный и эффективный доступ ко всем ресурсам компьютера, средства программирования высокого уровня, переносимость программ между различными платформами и операционными системами. С++, сохраняя совместимость с C, вносит возможности объектно-ориентированного программирования, выражая идею класса (объекта) как определяемого пользователем типа. Благодаря перечисленным качествам, C/C++ занял позицию универсального языка для любых задач. Но его применение может стать неэффективным там, где требуется получить готовый к употреблению результат в кратчайшие сроки, либо там, где невыгодным становится сам процедурный подход.

Delphi После продолжительной борьбы на фронте программных сред для Windows, Borland (ныне Inprise) ушла на рынок корпоративных систем. Delphi - это не продолжатель дела Borland Pascal / Borland C, его ниша - т.н. быстрое создание приложений (Rapid Application Developing, RAD). Подобные средства позволяют в кратчайшие сроки создать рабочую программу из готовых компонентов, не растрачивая массу усилий на мелочи. Особое место в таких системах занимают возможности работы с базами данных.

Java Как яркий пример специализации, язык Java появился в ответ на потребность в идеально переносимом языке, программы на котором эффективно исполняются на стороне клиента WWW. В ввиду специфики окружения, Java может быть хорошим выбором для системы, построенной на Internet/Intranet технологии.

Но более подробно остановимся на яэыке прграммирования - ассемблере.



Ассемблер для IBM PC

Ассемблером называется машинно-зависимый компилятор, преобразующий специальным образом составленные текстовые строки в машинные инструкции

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

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

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



Встроенный ассемблер

Встроенный ассемблер Borland Pascal позволяет вам непосредственно в программах Паскаля записывать код ассемблера процессоров.

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

За исключением директив DB (определить байт), DW (определить слово) и DD (определить двойное слово). Операции, реализуемые с помощью директив Турбо Ассемблера, близко соответствуют конструкциям Borland Pascal. Например, большинство директив EQU соответствуют описаниям Borland Pascal const, var и type, директива PROC - описаниям procedure и function, а директива STRUC - типам record Borland Pascal. Фактически, встроенный ассемблер Borland Pascal можно рассматривать, как компилятор языка ассемблера, использующий для всех описаний синтаксис Паскаля.

Регистры

Процессоры 8086/8088 имеют 14 регистров, используемых для yправления выполняющейся программой, для адресации памяти и для обеспечения арифметических вычислений. Каждый регистр имеет длину в одно слово (16 бит) и адресуется по имени. Биты регистра принято нумеровать слева направо:

15  14   13  12  11  10   9  8  7   6  5  4  3  2  1   0 

Процессоры 80286 и 80386 имеют ряд дополнительных регистров, некоторые из них 16-битовые. Эти регистры здесь не рассматриваются.

В функциональном отношении регистры делятся на группы:

    Регистры  общего назначения(AX, BX, CX, DX)

    Регистры сегментные(CS, DS, SS, ES)

    Регистровые  указатели(SP, BP, IP)

    Регистры индексные(SI и DI)

                    Флаговый регистр

Регистры общего назначения: AX, BX, CX и DX

При программировании на ассемблере регистры общего назначения являются "рабочими лошадками". Особенность этих регистров состоит в том, что возможна адресация их как одного целого слова или как oднобайтовой части. Левый байт является старшей частью (high), a правый - младшей частью (low). Например, двухбайтовый регистр CX состоит из двух однобайтовых: CH и CL, и ссылки на регистр возможны по любому из этих трех имен. Следующие три ассемблерные команды засылают нули в регистры CX, CH и CL, соответственно:

MOV      CX,00

MOV      CH,00

MOV      CL,00

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

    AX: │ AH │ AL │

2.Регистр BX. Регистр BX является базовым регистром. Это единственный регистр общего назначения, который может использоваться в качестве "индекса" для расширенной адресации. Другое общее применение его - вычисления.

    BX: │ BH │ BL │

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

    CX: │ CH │ CL │

4.Регистр DX. Регистр DX является регистром данных. Он применяется для некоторых операций ввода/вывода и тех операций умножения и деления над большими числами, кото рые используют регистровую пару DX и AX.

     DX: │ DH │ DL │

Любые регистры общего назначения могут использоваться для cложения и вычитания как 8-ми, так и 16-ти битовых значений.

Сегментные регистры CS, DS, SS и ES

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

1.Регистр CS. Регистр сегмента кода содержит начальный адрес сегмента кода. Этот адрес плюс величина смещения в командном указателе (IP) определяет адрес команды, которая должна быть выбрана для выполнения. Для обычных программ нет необходимости делать ссылки на регистр CS.

2.Регистр DS. Регистр сегмента данных содержит начальный адрес сегмента данных. Этот адрес плюс величина смещения, определенная в команде, указывают на конкретную ячейку в сегменте данных.

3. Регистр SS. Регистр сегмента стека содержит начальный адрес в сегменте стека.

4.Регистр ES. Некоторые операции над строками используют дополнительный сегментный регистр для управления адресацией памяти. В данном контексте регистр ES связан с индексным регистром DI. Если необходимо использовать регистр ES, ассемблерная программа должна его инициализировать.

Регистровые указатели: SP, BP, IP

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

Регистр IP содержит смещение на команду, которая должна быть выполнена. Обычно этот регистр в программе не используется, но он может изменять свое значение при использовании отладчика DOS DEBUG для тестирования программы.

1. Регистр SP. Указатель стека обеспечивает использование стека в памяти, позволяет временно хранить адреса и иногда данные. Этот регистр связан с регистром SS для адресации стека.

2. Регистр BP. Указатель базы облегчает доступ к параметрам: данным и адресам переданным через стек.

Индексные регистры: SI и DI

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

1. Регистр SI. Этот регистр является индексом источника и применяется для некоторых операций над строками. В данном контексте регистр SI связан с регистром DS.

2. Регистр DI. Этот регистр является индексом назначения и применяется также для строковых операций. В данном контексте регистр DI связан с регистром ES.

Флаговый регистр

Девять из 16 битов флагового регистра являются активными и определяют текущее состояние машины и результатов выполнения. Многие арифметические команды и команды сравнения изменяют состояние флагов. Назначение флаговых битов:

Флаг Назначение
O (Переполнение) Указывает на переполнение старшего бита при арифметических командах.
D (Направление) Обозначает левое или правое направление пересылки или сравнения строковых данных (данных в памяти превышающих длину одного слова).
I (Прерывание) Указывает на возможность внешних прерываний.
T (Пошаговый режим) Обеспечивает возможность работы процессора в пошаговом режиме. Например, программа DOS DEBUG устанавливает данный флаг так, что возможно пошаговое выполнение каждой команды для проверки изменения содержимого регистров и памяти.
S (Знак) Содержит результирующий знак после арифметических операций(0 - плюс, 1 - минус).
Z (Ноль) Показывает результат арифметических операций и операций сравнения (0 - ненулевой, 1 - нулевой результат).
A (Внешний перенос) Содержит перенос из 3-го бита для 8-битных данных, используется для специальных арифметических операций.
P (Контроль четности) Показывает четность младших 8-битовых данных (1 - четное и 0 - нечетное число).
C (Перенос) Содержит перенос из старшего бита, после арифметических операций, а также последний бит при сдвигах или циклических сдвигах.

При программировании на ассемблере наиболее часто используются флаги O, S, Z, и C для арифметических операций и операций сравнения, а флаг D для обозначения направления в операциях над строками.





Адресация

В архитектуре 8086/8088 адрес любого байта задается двумя 16-битовыми словами - сегментом и смещением. Архитектура МП позволяет использовать семь различных способов адресации.





Регистровая

Извлекает операнд из регистра или помещает его в регистр. Примеры:

        MOV   AX,   BX             Извлекаем из BX и помещаем в AX

        ADD  CX,   AX               Содержимое AX прибавляем к CX

        PUSH     CX                    Заталкиваем в стек содержимое CX





Непосредственная

Операнд(8- или 16-разрядная) содержится непосредстаенно в теле команды.Примеры:

        MOV  AX,   100           Загружаем в AX значение 100

        ADD  AX,   5               К содержимому AX прибавляем 5

         CX     0FFFFh             Помещаем в CX значение 65535





Прямая

Смещение операнда задается в теле программы и складывается с регистром DS; например:

   var

      X: Word;

      B: Byte;

- - - - - - - - - - - - - -

  MOV   AX,   X                   Пересылаем значение переменной X регистр AX

  ADD   AH,   B                   К содержимому регистра AH прибавляем значение переменной B



  MOV   X,  AX                   Пересылаем содержимое регистра AX в область памяти переменной X





Косвенная(косвенно-регистровая)

Исполнительный адрес операнда (точнее, его смещение - offset) находится в одном из регистров - BX, BP, SI, DI. Для указания косвенной адресации этот регистр должен заключаться в квадратные скобки, например:

  MOV   AX,  [BX]                   Содержимое 16-разрядного слова, хранящегося в памяти по адресу DS:BX,                                                                  пересылаем в регистр AX

Важно отметить, что каждый из этих регистров по умолчанию работает со своим сегментным регистром, а именно: DS:BX,   SS:BP,   DS:SI,   ES:DI.

В команде допускается явное указание сегментного регистра, если он отличается от умалчиваемого:

   MOV  AX,  ES:  [BX]





Базовая

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

   MOV   AX, [BX]+10             Загружаем в AX 10-й по счету байт от начала базы памяти по адресу DS:BX



Индексная

Один из индексных регистров SI или DI указывает положение элемента относительно начала некоторой области памяти. Пусть, например, АОВ - имя массива значений типа Byte. Тогда можно использовать такие фрагменты:

  MOV   SI,15                            Помещаем в SI константу 15

  MOV  AH, AOB[SI]                Пересылаем в AH 16-й по порядку байт от начала массива

  MOV  SI, 0

  MOV  AOB[SI], AH                Пересылаем полученное в самый первый элемент массива





По базе с индексированием

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

  MOV AX, [BX] [SI]

Этот тип адресации удобен при обработке двумерных массивов. Если, например, AOB есть массив из 10x10 байт вида

   var

         AOB:  array  [0..9,  0..9]  of  Byte;

то для доступа к элементу AOB[2,3]

  MOV BX, 20                               База строки 2

  MOV SI, 2                                   Номер 3-го элемента

  MOV AX, AOB[BX] [SI]             Доступ к элементу





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

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

Детальный анализ всех команд МП 8086/8088 занял бы слишком много места, поэтому в идущих за таблицами пояснениях рассматриваются лишь наиболее популярные команды.



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

Мнемоника Формат Пояснение
Команды общего назначения
MOV MOV приемник, источник Переслать значение
PUSH PUSH источник Поместить в стек
POP POP приемник Извлечь из стека
XCHG XCHG приемник, источник Обменять значения
XLAT XLAT таблица Загрузить в AL байт из таблицы
Команды ввода-вывода
IN IN аккумулятор, порт Читать из порта
OUT OUT порт, аккумулятор Записать в порт
Команды пересылки адреса
LEA LEA регистр 16, память 16 Загрузить исполнительный адрес
LDS LDS регистр 16, память32 Загрузить в DS:регистр16 полный адрес
LES LES регистр 16, память32 Загрузить в ES:регистр16 полный адрес
Команды пересылки флагов
LAHF LAHF Загрузить флаги в АН
SAHF SAHF Установить флаги из АН
PUSHF PUSHF Поместить флаги в стек
POPF POPF Извлечь флаги из стека


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

   mov  ах,  Table                     {Пересылка слова из памяти в АХ}

  mov  Table, ah                       {Пересылка байта из АН в память}

  mov  ds, ax                             {Пересылка в сегмент данных}

  mov  es:[bx], ax                       {Пересылка слова в память: базовая адресация с заменой сегмента}

  mov  ch, -17                            {Переслать константу в регистр}

  mov  Table, $FF                      {Переслать константу в память}

С помощью MOV нельзя пересылать:

  из памяти в память, например, вместо

      mov  Mem1, Mem2

  следует использовать

      mov  ax,  Mem2

      mov   Mem1,  ax

  константу или переменную в DS, например, нельзя

       mov  DS, Data_Seg

  нужно:

       mov  ax, Data_Seg

       mov  ds, ax

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

       mov  es,  ds

   но можно

        mov ax,ds

        mov es,ax

   в регистр CS; значение этого регистра (сегмента кода) автоматически меняется при выполнении дальних команд    CALL и JMP; кроме того, он загружается из стека при выполнении команды RETF (выход из дальней процедуры).

Для временного сохранения регистров и данных, а также для обмена значениями между регистрами широко используются стековые команды PUSH и POP. Каждая из них работает со словом, т.е. в стек нельзя поместить или извлечь из него одиночный байт. При выполнении PUSH вначале уменьшается на 2 содержимое указателя SP, а затем операнд помещается по адресу SS: SP. При извлечении из стека сначала читается память по адресу SS: SP, а затем SP увеличивается на 2. Таким образом, при заполнении указатель вершины стека SP смещается к младшим адресам, а при освобождении -к старшим. При работе со стеком следует помнить о специфике использования стековой памяти (<последним пришел - первым ушел>), а также о том, что эта память интенсивно используется при вызове процедур, т.е. состояние стека к моменту выхода из процедуры должно быть строго согласовано с дальнейшей работой программы. Первое условие определяет порядок извлечения данных из стека - он должен быть обратным порядку, в котором эти данные помещались в стек. Второе условие фактически означает, что после выхода из процедуры указательSP должен содержать то же смещение, что и к моменту входа в нее. Иными словами, процедура не должна <забыть> в стеке лишнее слово или взять из него больше нужного.

Команда загрузки адреса LEA загружает в регистр адрес (смещение) нужного участка памяти. Этого же можно достичь с помощью зарезервированного слова OFFSET, стоящего перед именем переменной. Например:

  var

      X: Word;

............................

  asm

      mov  ax,  OFFSET X                 {Загружаем смещение X в АХ}

      lea   ax,  X                                   {To же действие}

  end ;

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

Две другие команды адресной загрузки - LDS и LES загружают первое 16-разрядное слово из источника в регистр-приемник, а затем следующее слово - в регистр DS или ES, т.е. они рассчитаны на загрузку полного адреса операнда (сегмента и смещения).





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

Мнемоника Формат Комментарий
Команды сложения
ADD ADD приемник, источник Сложить
ADC ADC приемник, источник Сложить, добавить перенос
ААА ААА Скорректировать сложение для таблицы ASCII
DAA DAA Скорректировать сложение для двоично-десятичных чисел
INC INC приемник Увеличить на единицу
Команды вычитания
SUB SUB приемник, источник Вычесть
SBB SBB приемник, источник Вычесть с заемом
AAS AAS Скорректировать вычитание для таблицы ASCII
DAS DAS Скорректировать вычитание для двоично-десятичных чисел
DEC DEC приемник Уменьшить на единицу
NEG NEG приемник Обратить знак
СМР СМР приемник, источник Сравнить
Команды умножения
MUL MUL источник Умножить без знака
IMUL IMUL источник Умножить со знаком
AАМ ААМ Скорректировать умножение для таблицы ASCII
Команды деления
DIV DIV источник Делить без знака
IDIV IDIV источник Делить со знаком
AAD AAD Скорректировать деление для таблицы ASCII
Команды расширения знака
CBW CBW Преобразовать байт в слово
CWD CWD Преобразовать слово в двойное слово



При использовании арифметических команд следует помнить о том, что МП может обрабатывать знаковые числа, числа без знака, а также двоично-десятичные числа. В беззнаковых числах для представления значения используются все биты. т.е. они эквивалентны типам Byte и Word, в то время как знаковые числа в старшем разряде хранят знак числа и эквивалентны типам Shortlnt и Integer. Двоично-десятичные числа используют по 4 бита для каждого десятичного разряда и могут быть упакованными или неупакованными. В первом случае один байт хранит 2 десятичные цифры (старшая - в старшем полубайте), во втором - только одну (старший полубайт не используется). Основные арифметические команды МП (ADD, SUB, MUL, DIV) не учитывают двоично-десятичную форму представления чисел, поэтому в архитектуру МП включены команды коррекции результата.





Битовые команды

Мнемоника Формат Комментарий
Логические команды
AND AND приемник, источник Выполнить AND
OR OR приемник, источник Выполнить OR
XOR XOR приемник, источник Выполнить XOR
NOT NOT приемник Выполнить NOT
TEST TEST приемник, источник Проверить
Сдвиговые команды
SAL/SHL SAL приемник, счетчик Сдвинуть влево
SAR/SHR SAR приемник, счетчик Сдвинуть вправо
ROL ROL приемник, счетчик Сдвинуть влево циклически
ROR ROR приемник, счетчик Сдвинуть вправо циклически
RCL RCL приемник, счетчик Сдвинуть влево с переносом
RCR RCR приемник, счетчик Сдвинуть вправо с переносом



Битовые команды используются при исчислении логических выражений, а также в тех случаях, когда необходимо изменить отдельные разряды операнда. Логические команды AND, OR, XOR и NOT эквивалентны соответствующим операциям Турбо Паскаля в случае, когда операндами являются целочисленные выражения. Команда TEST выполняет целочисленную операцию поразрядного суммирования AND, но не изменяет значения операндов, а лишь устанавливает флаги в соответствии со значением результата сравнения: обнуляет CF и OF, изменяет PF, ZF, SF и не меняет AF (флаг ZF установится в 1 в том случае, когда оба операнда содержат по единице хотя бы в одном соответствующем разряде). Команды сдвига SHL/SHR эквивалентны одноименным операциям Турбо Паскаля и отличаются от команд циклического сдвига ROLIROR тем, что вытесненные в ходе их выполнения значащие разряды теряются, в то время как при циклическом сдвиге эти разряды появляются <с другой стороны>. Например, если выполнить фрагмент

   mov  al, 1              {Загружаем в AL единицу}

    shr   al, 1              {Сдвигаем вправо ,на 1 разряд}

регистр AL будет содержать 0 (вытесненная вправо единица будет помещена в CF), в то время как после замены команды SHR на ROR в нем будет значение $80=128 (вытесненная единица будет помещена в старший бит регистра).

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





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

Мнемоника Формат Комментарий
Безусловные переходы
CALL CALL имя Войти в процедуру
RET RET [количество параметров] Вернуться из процедуры
JUMP JUMP имя Перейти
Условные переходы
JA/JNBE JA близкая_метка Перейти, если выше (после сравнения беззнаковых операндов)
JAE/JNB JAE близкая_метка Перейти, если выше или равно
JB/JBAE/JC JB близкая_метка Перейти, если ниже
JBE/JNA JBE близкая_метка Перейти, если ниже или равно
JCXZ JCXZ близкая_метка Перейти, если СХ=0
JE/JZ JE близкая_метка Перейти, если равно
JG/JNLE JG близкая_метка Перейти, если больше (после сравнения знаковых операндов)
JGE/JNL LGE близкая_метка Перейти, если больше или равно
JL/JNGE JL близкая_метка Перейти, если меньше
JLE/JNG JLE близкая_метка Перейти, если меньше или равно
JNC JNC близкая_метка Перейти, если нет переноса
JNE/JNZ JNE близкая_метка Перейти, если не равно
JNO JNO близкая_метка Перейти, если нет переполнения
JNP/ JPO JNP близкая_метка Перейти, если нечетный
JO JO близкая_метка Перейти, если перенос
JP/JPE JP близкая_метка Перейти, если четный
JS JS близкая_метка Перейти, если отрицательный
Команды управления циклами
LOOP LOOP близкая_метка Повторить цикл
LOOPE/LOOPZ LOOPE близкая_метка Повторять, пока равны
LOOPNE/LOOPNZ LOOPNE близкая_метка Повторять, пока не равны



Команды безусловных переходов CALL, RET, JMP могут использовать дальнюю или ближнюю модель памяти, в то время как команды условных переходов - только малую (в пределах -128...+127 байтов). При дальней модели памяти (устанавливается опцией Options/Compiler/Force far calls среды Турбо Паскаля или директивой компилятора {F+}) осуществляется как внутрисегментная, так и межсегментная передача управления, при ближней - только внутрисегментная.

Инструкция CALL работает следующим образом. Вначале адрес следующей за CALL инструкции (адрес возврата) помещается в стек, затем в регистр IP (или в пару CS:IP) помещается адрес точки входа в процедуру, таким образом сразу за командой CALL будет исполняться уже первая команда процедуры. Оба адреса (точки входа и возврата) будут 16-битовыми смещениями для внутрисегментного вызова или 32-битовыми полными адресами - для межсегментного. Все процедуры (функции) Паскаля, оттранслированные в режиме {F+} или содержащие зарезервированное слово FAR в заголовке, должны вызываться как дальние. Для этого за инструкцией CALL следует указать модель памяти:

Procedure MyProc; Far;

.......

asm

call FAR MyProc {Вызов дальней процедуры}

.......

end;

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

При выходе из дальней процедуры команда RET извлекает из стека оба 16-разрядных слова и помещает первое в IP, а второе в CS, а при выходе из ближней извлекает из стека только смещение и помещает его в IP.

Команды условных переходов способны передавать управление на метку, расположенную в пределах ближайших плюс-минус 128 байт от самой команды. Если нужно передать управление на метку, расположенную дальше в том же сегменте, или на метку в другом сегменте, сразу за командой условной передачи располагают безусловную команду JMP или CAL, например:

   cmp  ах, 0                 {Проверяем АХ}

   jne @NotZero          {AX=0 ?}

   jmp  IsZero               {Да - переходим на дальнюю метку}

  ................                   {Нет - продолжаем работу}

  ................

В таблице термин <выше/ниже> используется применительно к сравнению беззнаковых операндов, а <больше/меньше> - знаковых.

Поскольку условные переходы реализуют ветвление программы на основе проверки флагов, обычно непосредственно перед ними располагаются команды, изменяющие эти флаги, чаще всего - команда сравнения СМР. Ниже показаны комбинации СМР - условный_переход для различных соотношений приемника и источника (первого и второго операнда) команды СМР:

Условие Для беззнаковых чисел Для чисел со знаками
Приемник больше источника JA JG
Приемник и источник равны JE JE
Приемник меньше источника JB JL
Приемник не меньше источника JAE JGE
Приемник не больше источника JBE JLE
Приемник и источник не равны JNE JNE



   Например:

      сmр ах, 5                {АХ>5  ?}

      ja  @Above5           {Да, больше - переходим}

      сmp  bх, - 3             {ВХ<=-3 ?}

      jle  @LessM3          {Да, меньше или равен}

Команды LOOP/LOOPE/LOOPNE служат для организации циклов. Все они используют содержимое регистра СХ как счетчик числа повторений. Команда LOOP уменьшает СХ на единицу и передает управление на метку начала цикла, если содержимое этого регистра отлично от нуля. Команды LOOPE/LOOPNE также уменьшают счетчик СХ, но передают управление в начало цикла при совместном условии установки (или сброса) флага ZF и неравенства нулю счетчика СХ.

Вот как, например, можно отыскать нулевой байт в массиве АОВ:

   var

       АОВ:  array [1..1000] of Byte;

   .....................

  asm

       mov  cx, I000                           {Инициируем счетчик СХ}

       lea  bx,AOB                             {Помещаем адрес АОВ в ВХ}

       dec  bx                                      {Готовим цикл}

  {Здесь начало цикла проверки}

@@Test:  inc bx                             {Адрес очередного байта}

       cmp BYTE  PTR  [bx],0           {Проверяем байт}

       loopne @Test                           {Замыкаем цикл}

       jnz  @NotZero                         {Если не найден нулевой байт}

       .................                                 {Нашли нулевой байт}

   end;





Строковые команды

Мнемоника Формат Комментарий
Пересылка строк
MOVSB MOVSB Пересылать байты
MOVSW MOVSW Пересылать слова
Сравнение строк
CMPSB CMPSB Сравнивать байты
CMPSW CMPSW Сравнивать слова
Сканирование
SCASB SCASB Искать байт
SCASW SCASW Искать слово
Загрузка и сохранение
LODSB LODSB Загружать байты
LODSW LODSW Загружать слова
STOSB STOSB Сохранять байты
STOSW STOSW Сохранять слова



Строковые команды рассчитаны на обработку строк. Термин <строка> здесь отнюдь не эквивалентен аналогичному термину Турбо Паскаля и означает произвольную цепочку байт или слов длиной до 64 Кбайт. Эти команды оперируют пятью примитивами, каждый из которых обрабатывает лишь один байт или одно слово за раз. Перед примитивом обычно указывается префикс повторения REP/REPE/REPNE, заставляющий выполняться примитив до тех пор, пока не обнулится счетчик повторений СХ или не будет нарушено соответствующее условие.

При использовании строковых команд важно помнить два обстоятельства. Во-первых, эти команды всегда берут адрес строки-источника из пары DS:SI, а строки-приемника - из пары ES:DI. Таким образом, перед исполнением строковой команды необходимо инициировать сегментные регистры нужным образом. Во-вторых, строковые команды используют индексную адресацию с автоматическим изменением смещения в SI/DI после однократного исполнения примитива. Содержимое этих регистров изменяется на 1 при обработке байтов и на 2 при обработке слов, причем наращивается, если флаг направления DF сброшен, и уменьшается, если он равен 1.

Вот как можно осуществить пересылку массива А в массив В:

   var

       А,В:  array [1..250] of Integer;

   ................

   asm

       lea  si, A                        {Смещение А - в SI (источник)'}

       push  ds

       pop  es                           {Инициируем ES := DS}

       lea  di,B                         {Смещение В - в DI (приемник)}

       mov  cx,250                   {Счетчик- переноса}

       сld                                  {Направление переноса - наращивать}

  rep  movsw                          {Переносим 500 байт}

  end;

В программе на Турбо Паскале регистр DS всегда содержит сегмент данных, поэтому инициировать его необязательно. Что касается регистра дополнительного сегмента ES, такого правила нет, и хотя в большинстве случаев он также ссылается на сегмент данных, рекомендуется проводить его инициацию перед использованием строковой команды (см. выше команды push ds, popes).





Команды прерываний

Мнемоника Формат Комментарий
INT INT номер Выполнить прерывание
INTO INTO Выполнить прерывание по переполнению
IRET IRET Вернуться из прерывания



Выполнение прерываний во многом напоминает косвенный вызов дальней процедуры. По команде INT (INTO) в стек помещается регистр флагов, сегмент CS и указатель IP, а новые значения этих регистров берутся из 4-байтного вектора прерывания, соответствующего номеру прерывания в команде INT, или из вектора 4 -для команды INTO. Таким образом, единственным отличием от команды CALL является то, что в стек предварительно заносится регистр флагов. Следует, правда, оговориться: перед передачей управления программе обработки прерывания микропроцессор сбрасывает флаги трассировки TF и прерываний IF; сброс TF необходим для обеспечения нормальной работы отладчиков, использующих прерывание по вектору 1 или 4, сброс IF блокирует вмешательство других процессов в ход обработки прерывания.

Команда INTO представляет собой условное прерывание и выполняется, если в этот момент взведен флаг переполнения OF. Команда IRET реализует правильный выход из программы обработки прерывания: она считывает из стека 3 двухбайтные слова и помещает их в регистры IP, CS и регистр флагов.





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

Мнемоника Формат Комментарий
Управление флагами
STC STC Установить перенос
CLC CLC Очистить перенос
CMC CMC Инвертировать CF
STD STD Установить направление
CLD CLD Очистить направление
STI STI Разрешить прерывания
CLI CLI Запретить прерывания
Внешняя синхронизация
HLT HLT Остановить вычисления
WAIT WAIT Ждать активности на шине
ESC ESC код, источник Передать команду
LOCK LOCK Захватить шину
Пустая команда
NOP NOP Нет операции







Команды внешней синхронизации

Команды внешней синхронизации работают следующим образом.

HALТ переводит МП в состояние останова, из которого его можно вывести только при перезагрузке системы или при наступлении немаскируемого прерывания.

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

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

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



Страница 1| Старница 2