Команды условного перехода и регистр ЕСХ/СХ



Архитектура процессора предполагает специфическое использование многих ре­гистров. К примеру, регистр EAX/AX/AL используется как аккумулятор, а регистры ЕВР/ВР, ESP/SP — для работы со стеком. Регистр ЕСХ/СХ тоже имеет определенное функциональное назначение — он выполняет функции счетчика в командах управления циклами и при работе с цепочками символов. Возможно, что функци­онально команды условного перехода, связанные с регистром ЕСХ/СХ, правильнее было бы отнести к этой группе команд.

Синтаксис команд JCXZ (Jump ifcx is Zero — переход, если СХ ноль) и JECXZ (Jump Equal ecx Zero — переход, если ЕСХ ноль) таков: jcxz/jecxz метка_перехода

Эти команды очень удобно использовать при организации цикла и при работе с цепочками символов. В этой главе мы разберемся со средствами организации цик­лов в программах на языке ассемблера и покажем работу команд JCXZ/JECXZ. Гла­ва 12 будет посвящена цепочечным командам, где мы еще раз вернемся к коман­дам JCXZ/JECXZ. Нужно отметить свойственное им ограничение. В отличие от других команд условной передачи управления, команды JCXZ/J ECXZ могут адресовать толь­ко короткие переходы — на -128 байт или на +127 байт от следующей за ней ко­манды.

 

17. Организация циклов в Ассемблере. Примеры.

Организация циклов (стр.229-234 в уч. Юрова “Assembler”)

Цикл, как известно, представляет собой важную алгоритмическую структуру, без которой не обходится, наверное, ни одна программа. Организовать циклическое выполнение некоторого фрагмента программы можно, к примеру, используя ко­манды условной передачи управления или команду безусловного перехода JMP. Например, подсчитаем количество нулевых байтов в области mas (листинг 10.2).

Листинг 10,2. Подсчет числа нулевых элементов

<1> ;prg_10_2.asm

<2> model small

<3> .stack 100h

<4> .data

<5> len equ 10  количество элементов в mas

<6> mas db 1,0,9,8,0,7,8,0,2,0

<7> .code

<8> start:

<9>mov ax,@data

<10>mov ds , ах

<11>mov cx, len ;длину поля mas в сх

<12>xor ax ax

<13>xor si,si

<14>cycl.:

<15>jcxz exit ;проверка сх на 0, если 0, то выход

<16> cmp mas[si],0 ;сравнить очередной элемент mas с 0

<17>jne ml ;если не равно 0, то на ml

<18>inc аТ ;в аТ, - счетчик нулевых элементов

<19>m1:

<20>inc si ;перейти к следующему элементу

<21>dec сх уменьшить сх на 1

<22>jmp cycl

<23>exit:

<24>mov ax,4c00h

<25> int 21h ;возврат управления операционной системе

<26>end start

Цикл в листинге 10.2 организован тремя командами, JCXZ, DEC и JMP (строки 15, 21 и 22). Команда JCXZ выполняет здесь две функции: предотвращает выполнение «пустого» цикла (когда счетчик цикла в СХ равен нулю) и отслеживает окончание цикла после обработки всех элементов поля mas. Команда DEC после каждой итера­ции цикла уменьшает значение счетчика в регистре СХ на 1. Заметьте, что при та­кой организации цикла все операции по его организации выполняются «вручную». Но, учитывая важность такого алгоритмического элемента, как цикл, разработчи­ки процессора ввели в систему команд группу из трех команд, облегчающую про­граммирование циклов. Эти команды также используют регистр ЕСХ/СХ как счет­чик цикла. Дадим краткую характеристику этим командам.

Команда LOOP позволяет организовать циклы (loops), подобные циклам for в языках высокого уровня с автоматическим уменьшением счетчика цикла.

Син­таксис команды: loop метка_перехода

Команда реализует описанные далее действия.

Декремент регистра ЕСХ/СХ.

Сравнение регистра ЕСХ/СХ с нулем:

- если (ЕСХ/СХ) > 0, то управление передается на метку перехода;

- если (ЕСХ/СХ) = 0, то управление передается на следующую после LOOP ко­манду.

 

Команды LOOPE и LOOPZ (Loop still сх <> 0 or Zero flag = 0 — повторить цикл пока СХ <> 0 или ZF = 0) — абсолютные синонимы, поэтому используйте ту команду, ко­торая вам больше нравится. Синтаксис команд: loope/loopz метка_перехода

Команды реализуют описанные далее действия.

Декремент регистра ЕСХ/СХ.

Сравнение регистра ЕСХ/СХ с нулем и анализ состояния флага нуля ZF:

- если (ЕСХ/СХ) > 0 и ZF = 1, управление передается на метку перехода;

- если (ЕСХ/СХ) = 0 ranZF= 0, управление передается на следующую после ШОР команду.

 

Команды LOOPNE и LOOPNZ (Loop still сх <> 0 or NonZero flag = 0 — повторить цикл, пока СХ <> 0 или ZF= 1) также абсолютные синонимы.

Синтаксис команд: loopne/loopnz метка_перехода

Команды реализуют описанные далее действия.

Декремент регистра ЕСХ/СХ.

Сравнение регистра ЕСХ/СХ с нулем и анализ состояния флага нуля ZF:

если (ЕСХ/СХ) > 0 и ZF = 0, управление передается на метку перехода;

если (ЕСХ/СХ) = 0 или ZF = 1, управление передается на следующую после LOOP команду.

 

Команды LOOPE/LOOPZ и LOOPNE/LOOPNZ по принципу своей работы являются взаимнообратными. Они расширяют действие команды LOOP тем, что дополнитель­но анализируют флаг ZF. Это дает возможность организовать досрочный выход из цикла, используя этот флаг в качестве индикатора. Типичное применение этих команд связано с операцией поиска определенного значения в последовательно­сти или со сравнением двух чисел.

Недостаток команд организации цикла LOOP, LOOPE/LOOPZ и LOOPNE/LOOPNZ за­ключается в том, что они реализуют только короткие переходы (от -128 до +127 байт). Для работы с длинными циклами придется использовать команды условного перехода и команду JMP (см. листинг 10.2), поэтому постарайтесь осво­ить оба способа организации циклов. Рассмотрим несколько примеров организа­ции циклов с помощью команд LOOP, LOOPE/LOOPZ и LOOPNE/LOOPNZ.

Программа из листинга 10.2 с использованием команды организации цикла будет выглядеть так, как показано в листинге 10.3.

Заметьте, что у команды JCXZ в строке 14 осталась только одна функция — не допустить выполнения «пустого» цикла, поэтому несколько изменилось ее место в тексте программы: теперь она стоит перед меткой начала цикла cycl. Изменение и контроль содержимого регистра СХ в процессе выполнения каждой итерации вы­полняет команда LOOP (строка 21).

Рассмотрим пример, в котором продемонстрируем типичный подход к исполь­зованию команды LOOPNZ. В программе из листинга 10.4 ищется первый нулевой элемент в поле mas. Интерес представляют строки 20 и 21. Команда LOOPNZ на ос­новании содержимого регистра СХ и флага ZF принимает решение о продолжении цикла. Выход из цикла происходит в одном из двух случаев: СХ = 0 (просмотрены все элементы поля mas) или ZF = 1 (командой СМР обнаружен нулевой элемент). Назначение следующей команды JZ (строка 21) в том, чтобы распознать конкрет­ную причину выхода из цикла. Если выход из цикла произошел после просмотра строки, в которой нет нулевых элементов, то флаг JZ не сработает и будет выдано сообщение об отсутствии нулевых элементов в строке (строки 7, 23-25). Если вы­ход из цикла произошел в результате обнаружения нулевого элемента, то в регис­тре SI окажется номер позиции этого элемента в поле mas и при необходимости можно продолжить обработку. В нашем случае мы просто завершаем программу — переходим на метку exit.

Читатели, имеющие даже небольшой опыт программирования на языках высо­кого уровня, знают, что очень часто возникает необходимость во вложенных цик­лах. Самый простой пример — обработка двухмерного массива. Работу с массива­ми, в том числе двухмерными, мы рассмотрим в главе 13, пока же разберемся с основными принципами организации вложенных циклов. Основная проблема, которая при этом возникает, — как сохранить значения счетчиков в регистре ЕСХ/ СХ для каждого из циклов. Для временного сохранения счетчика внешнего цикла на время выполнения внутреннего доступно несколько способов: задействовать регистры, ячейки памяти или стек. В следующем фрагменте программы имеется три цикла, вложенные один в другой. Этот фрагмент можно рассматривать как шаблон для построения других программ с вложенными циклами.

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

18. Работа с массивами. Примеры.

Массивы

Дадим формальное определение:

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

 

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

Как описать массив в программе?

Как инициализировать массив, то есть как задать начальные значения его элементов?

Как организовать доступ к элементам массива?

Как организовать массивы с размерностью более одной?

Как организовать выполнение типовых операций с массивами?

 

Описание и инициализация массива в программе

 

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

Перечислением элементов массива в поле операндов одной из директив описания данных. При перечислении элементы разделяются запятыми. К примеру: 

1. ;массив из 5 элементов.Размер каждого элемента 4 байта:

mas dd 1,2,3,4,5

 

2. Используя оператор повторения dup. К примеру: 

;массив из 5 нулевых элементов.

;Размер каждого элемента 2 байта:

mas   dw      5 dup (0)

 

Такой способ определения используется для резервирования памяти с целью размещения и инициализации элементов массива.

 

3. Используя директивы label и rept. Пара этих директив может облегчить описание больших массивов в памяти и повысить наглядность такого описания. Директива rept относится к макросредствам языка ассемблера и вызывает повторение указанное число раз строк, заключенных между директивой и строкой endm. К примеру, определим массив байт в области памяти, обозначенной идентификатором mas_b. В данном случае директива label определяет символическое имя mas_b, аналогично тому, как это делают директивы резервирования и инициализации памяти. Достоинство директивы label в том, что она не резервирует память, а лишь определяет характеристики объекта. В данном случае объект — это ячейка памяти. Используя несколько директив label, записанных одна за другой, можно присвоить одной и той же области памяти разные имена и разный тип, что и сделано в следующем фрагменте: 

...

n=0

...

mas_b label  byte

mas_w label  word

rept    4

           dw      0f1f0h

endm

 

 

В результате в памяти будет создана последовательность из четырех слов f1f0. Эту последовательность можно трактовать как массив байт или слов в зависимости от того, какое имя области мы будем использовать в программе — mas_b или mas_w.

 

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

Посмотрим на примере листинга 2, каким образом это делается. 

 Листинг 2 Инициализация массива в цикле

;prg_12_1.asm

MASM

MODEL small

STACK 256

.data

mes    db      0ah,0dh,'Массив- ','$'

mas   db      10 dup (?) ;исходный массив

i          db      0

.code

main:

           mov   ax,@data

           mov   ds,ax

           xor     ax,ax ;обнуление ax

           mov   cx,10 ;значение счетчика цикла в cx

           mov   si,0     ;индекс начального элемента в cx

go:                                                     ;цикл инициализации

           mov   bh,i    ;i в bh

           mov   mas[si],bh        ;запись в массив i

           inc      i                          ;инкремент i

           inc      si                   ;продвижение к следующему

                  ;элементу массива

           loop   go       ;повторить цикл

;вывод на экран получившегося массива

           mov   cx,10

           mov   si,0

           mov   ah,09h

           lea      dx,mes

           int      21h

show:

           mov   ah,02h ;функция вывода значения

                                                           ;из al на экран

           mov   dl,mas[si]

           add    dl,30h ;преобразование числа в символ

           int      21h

           inc      si

           loop   show

exit:

           mov   ax,4c00h          ;стандартный выход

           int      21h

end    main                  ;конец программы

 

Доступ к элементам массива

 

При работе с массивами необходимо четко представлять себе, что все элементы массива располагаются в памяти компьютера последовательно.

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

 

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

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

 

Давайте еще раз обратимся к описанию массива. К примеру, в программе статически определена последовательность данных: mas   dw      0,1,2,3,4,5

 

Пусть эта последовательность чисел трактуется как одномерный массив. Размерность каждого элемента определяется директивой dw, то есть она равна 2 байта. Чтобы получить доступ к третьему элементу, нужно к адресу массива прибавить 6. Нумерация элементов массива в ассемблере начинается с нуля.

То есть в нашем случае речь, фактически, идет о 4-м элементе массива — 3, но об этом знает только программист; микропроцессору в данном случае все равно — ему нужен только адрес.

 

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

 

база + (индекс*размер элемента)

 

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

 Вспомним эти режимы:

- индексная адресация со смещением — режим адресации, при котором эффективный адрес формируется из двух компонентов:

     --постоянного (базового) — указанием прямого адреса массива в виде имени идентификатора, обозначающего начало массива;

     --переменного (индексного) — указанием имени индексного регистра.

К примеру: mas dw      0,1,2,3,4,5

...

           mov   si,4

;поместить 3-й элемент массива mas в регистр ax:

           mov   ax,mas[si]

 

- базовая индексная адресация со смещением — режим адресации, при котором эффективный адрес формируется максимум из трех компонентов:

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

     -- переменного (базового) — указанием имени базового регистра;

     -- переменного (индексного) — указанием имени индексного регистра.

 

Этот вид адресации удобно использовать при обработке двухмерных массивов. Пример использования этой адресации мы рассмотрим далее при изучении особенностей работы с двухмерными массивами.

 

Напомним, что в качестве базового регистра может использоваться любой из восьми регистров общего назначения. В качестве индексного регистра также можно использовать любой регистр общего назначения, за исключением esp/sp.

 

Микропроцессор позволяет масштабировать индекс. Это означает, что если указать после имени индексного регистра знак умножения “*” с последующей цифрой 2, 4 или 8, то содержимое индексного регистра будет умножаться на 2, 4 или 8, то есть масштабироваться.

 

Применение масштабирования облегчает работу с массивами, которые имеют размер элементов, равный 2, 4 или 8 байт, так как микропроцессор сам производит коррекцию индекса для получения адреса очередного элемента массива. Нам нужно лишь загрузить в индексный регистр значение требуемого индекса (считая от 0). Кстати сказать, возможность масштабирования появилась в микропроцессорах Intel, начиная с модели i486. По этой причине в рассматриваемом здесь примере программы стоит директива .486. Ее назначение, как и ранее использовавшейся директивы .386, в том, чтобы указать ассемблеру при формировании машинных команд на необходимость учета и использования дополнительных возможностей системы команд новых моделей микропроцессоров.

 

Двухмерные массивы

 

С представлением одномерных массивов в программе на ассемблере и организацией их обработки все достаточно просто. А как быть если программа должна обрабатывать двухмерный массив? Все проблемы возникают по-прежнему из-за того, что специальных средств для описания такого типа данных в ассемблере нет. Двухмерный массив нужно моделировать. На описании самих данных это почти никак не отражается — память под массив выделяется с помощью директив резервирования и инициализации памяти.

 

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

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

 

Если последовательность однотипных элементов в памяти трактуется как двухмерный массив, расположенный по строкам, то адрес элемента (i, j) вычисляется по формуле

 

(база + количество_элементов_в_строке * размер_элемента * i+j)

 

Здесь i = 0...n–1 указывает номер строки, а j = 0...m–1 указывает номер столбца.

 

Например, пусть имеется массив чисел (размером в 1 байт) mas(i, j) с размерностью 4 на 4

(i= 0...3, j = 0...3):

           23      04      05      67

           05      06      07      99

           67      08      09      23

           87      09      00      08

 

В памяти элементы этого массива будут расположены в следующей последовательности:

 

23 04 05 67 05 06 07 99 67 08 09 23 87 09 00 08

 

Если мы хотим трактовать эту последовательность как двухмерный массив, приведенный выше, и извлечь, например, элемент

mas(2, 3) = 23, то проведя нехитрый подсчет, убедимся в правильности наших рассуждений:

 

Эффективный адрес mas(2, 3) = mas + 4 * 1 * 2 + 3 = mas + 11

 

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

 

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

--- сочетание прямого адреса, как базового компонента адреса, и двух индексных регистров для хранения индексов: mov ax,mas[ebx][esi]

--- сочетание двух индексных регистров, один из которых является и базовым и индексным одновременно, а другой — только индексным: mov ax,[ebx][esi]

19. Прерывания и подпрограммы обработки прерываний - основные определения, типы прерываний. Действия процессора по обработке аппаратных и про­граммных прерываний.

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

Система прерываний представляет собой комплекс аппаратных и программных средств. Аппаратные средства системы прерываний либо входят в состав CPU и называются тогда блоком прерываний, либо реализуются в виде отдельного устройства, называемого контроллером прерываний (Programmable Interupt Controller – PIC). Первый подход является типичным для больших ЭВМ класса Mainframe, второй – для компьютеров на базе микропроцессоров. Программные средства системы прерываний представляют собой так называемые обработчики прерываний, которые входят в состав операционной системы.

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

Роль процессора в обработке прерывания ввода вывода:

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

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

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

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

4. Процессор выполняет действия, предшествующие передаче управления по программе обработки прерывания. Прежде всего нужно позаботиться о сохранении текущего состояния процессора, что позволит в дальнейшем возобновить выполнение прерванной программы с той же точки. Здесь нужно обратить внимание на то, что в этот момент в счетчике команд процессора находится адрес команды, которая должна была бы выполняться процессором, если бы не произошло прерывание. Эту команду (а точнее, ее адрес) принято называть точкой прерывания, и она же является точкой возврата из прерывания. Поэтому процессор должен каким-то образом сохранить состояние счетчика команд, регистра состояния, который содержит слово состояния процессора PSW (processor status word). Как правило, эта информация помещается в системный стек.

5. Затем процессор загружает в счетчик команд начальный адрес программы (подпрограммы) обработки прерывания.

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

7. После этого подпрограмма приступает к собственно обработке прерывания. Этот процесс, как правило, включает анализ состояния модуля ввода-вывода, вызвавшего прерывание, и прием или передачу порции данных.

8. После завершения обработки подпрограмма восстанавливает содержимое в регистрах, которое было сохранено в стеке в самом начале выполнения, и только после этого выполняет последнюю команду -- команду возврата из прерывания.

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

20. Структуры обработчиков аппаратных прерываний.

 

21. Работа с Ассемблер в программах на языках высокого уровня. Примеры.

Программа на языке ассемблере пишется в виде так называемой ассемблерной вставки:

_asm

                           {

                                           код на ASM

}

?!

 

22. Макросы. Понятия макроопределений и макрокоманд. Использование макросов в программе.

Макрос = Макрокоманда

 

Идейно макрокоманда представляет собой дальнейшее развитие механизма замены текста.

С помощью макрокоманд в текст программы можно вставлять последовательности строк (которые логически могут быть данными или командами) и даже более того — привязывать их к контексту места вставки.

 

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

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

Дальнейшее наше обсуждение будет посвящено тому, как это сделать.

 

Определимся с терминологией.

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

 

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

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

 

имя_макрокоманды  macro   список_формальных_аргументов

тело макроопределения 

endm

 

Где должны располагаться макроопределения?

Есть три варианта:

 

1. В начале исходного текста программы до сегмента кода и данных с тем, чтобы не ухудшать читабельность программы.

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

 

2. В отдельном файле.

Этот вариант подходит при работе над несколькими программами одной проблемной области. Чтобы сделать доступными эти макроопределения в конкретной программе, необходимо в начале исходного текста этой программы записать директиву include имя_файла, к примеру: masm

model small

include show.inc

;в это место будет вставлен текст файла show.inc

...

 

3. В макробиблиотеке.

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

 

23. Процедуры и модульное программирование. Синтаксис определения, директивы NEAR, FAR.

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

 

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

 

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

 

Near/Far определяют тип вызовов – ближний/дальний (внутрисегментный вызов или нет).

 

Процедуры NEAR вызываются с помощью вызова ближнего типа и содержат ближний возврат управления. Вы должны вызывать их только в том же сегменте, в котором они определены. Вызов ближнего типа заносит адрес возврата в стек и устанавливает указатель инструктор (IP) в значение смешения процедуры. Поскольку сегмент кода (CS) не изменяется, процедура должна находиться в том же сегменте, что и вызывающая программа. Когда процессор обнаруживает возврат ближнего типа, он извлекает из стека адрес возврата и снова устанавливает в него IP. Сегмент кода не изменяется.

     Процедура FAR вызывается с помощью вызова дальнего типа и содержит возврат дальнего типа. Процедуры FAR вы можете вызывать вне сегмента, в котором они определяются. Вызов FAR заносит в стек адрес в виде сегмента и смещения, а затем устанавливает CS:IP в адрес процедуры. Когда процессор обнаруживает возврат дальнего типа, он извлекает из стека сегмент и смещение адреса возврата и устанавливает в него CS:IP.

 

Расстояние (NEAR или FAR), используемое в процедуре по умолчанию, определяется текущей выбранной моделью. Для моделей TINY, SMALL и COMPACT по умолчанию процедура будет ближней (NEAR). Для всех других моделей по умолчанию выбирается расстояние FAR. Если вы не используете упрощенные директивы определения сегментов, то по умолчанию процедура всегда будет ближней (NEAR).

 

     Примечание: FAR или NEAR можно задать в качестве аргумента оператора MODEL.

 

     Вы можете переопределить используемое по умолчанию расстояние, задав нужное расстояние в определении процедуры. Для этого вы можете использовать ключевые слова NEAR или FAR. Эти ключевые слова переопределяют расстояние, используемое в процедуре по умолчанию, но только для текущей процедуры.

24. Технология MMX. Основные определения, способы применения, особенности.

 

25. Регистры MMX, способы работы с данными, арифметические, логические и команды пересылки.

 


Дата добавления: 2018-04-04; просмотров: 538; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!