- •Министерство образования российской федерации ижевский государственный технический университет
- •1. Методика выполнения лабораторных работ
- •2. Основные сведения об ассемблере
- •2.1. Регистры процессора
- •2.2. Команды ассемблера
- •2.3. Прерывания ассемблера
- •4. Режимы адресации команд
- •5. Байт способа адресации
- •6. Режимы адресации переходов
- •7. Система команд
- •7.1. Команды пересылки
- •7.1.1. Общие команды пересылки данных
- •7.1.1.2. Xchg - перестановка
- •7.1.1.3. Xlat - перекодировка
- •7.1.1.7. Команда lahf - загрузка флагов в регистр ан
- •7.1.1.8. Sahf - установка флагов из регистра ан
- •7.1.2. Команды пересылки данных с использованием стека (стековые команды)
- •7.1.3. Команды ввода - вывода
- •1.4. Команды пересылки цепочек байт или слов (цепочечные команды)
- •7.1.4.1. Movs - пересылка строки байтов или слов
- •7.1.4.2. Movsb/movsw - пересылка строки байтов или слов
- •7.1.4.3. Lods - загрузка строки байтов или слов
- •7.1.4.8. Cmpsb/cmpsw - сравнение строки байтов или слов
- •7.1.4.9. Scas - сканирование строки байтов или слов
- •7.1.4.10. Scasb/scasw - сканирование строки байтов или слов
- •7.2. Арифметические команды
- •7.2.1. Команды сложения
- •7.2.2. Команды вычитания
- •7.2.3. Команды сравнения
- •7.2.4. Команды умножения
- •7.2.4.2. Imul - умножение знаковых величин
- •7.2.5. Команды деления
- •7.2.5.2. Idiv - деление знаковых величин
- •7.3. Логические команды
- •7.4. Команды сдвигов
- •7.5. Команды переходов (передачи управления)
- •7.5.1. Команды безусловных переходов
- •7.5.2. Команды условных переходов
- •7.5.3. Команды вызовов (подпрограммы)
- •7.5.4. Команды возвратов (из подпрограмм)
- •7.5.5. Команды управления циклами
- •7.5.6. Команды прерываний
- •7.6. Команды управления микропроцессором
- •8. Примеры выполнения лабораторных работ
- •9. Учебно-методическая литература
- •Описание команд отладчика debug
- •Команды процессора 8086
- •1. Команды пересылки данных
- •1.1. Общие команды пересылки данных
- •Xlat Перекодировка
- •Xchg Перестановка
- •1.2. Стековые команды
- •1.3. Команды ввода-вывода
- •In Ввод байта или слова из порта
- •1.4. Команды пересылки цепочек
- •2. Арифметические команды
- •2.1. Команды сложения
- •Inc Инкремент
- •2.2. Команды вычитания
- •2.3. Команды сравнения
- •2.4. Команды умножения
- •Imul Целое умножение знаковых величин
- •2.5. Команды деления
- •Idiv Целое деление знаковых величин
- •3. Логические команды
- •Xor Исключающее или
- •4. Команды сдвигов
- •5. Команды передачи управления
- •5.1. Команды вызова процедуры
- •5.2. Команды прерываний
- •Int Прерывание
- •Into Прерывание по переполнению
- •Iret Возврат из обработки прерывания
- •5.3. Команды условных переходов
- •5.4. Команды безусловных переходов
- •5.5. Команды управления циклами
- •6. Команды управления процессором
2.2. Команды ассемблера
В общем случае значения помещаются в регистры с помощью команды MOV. Команда MOV AX,BX пересылает содержимое регистра BX в AX, затирая ранее содержащееся в AX значение. Команда MOV AH,BL приводит к пересылке байта из регистра BL в регистр AH, но MOV AX, BL - недопустимая команда, так как в регистре AX содержится слово, в регистре BL - байт, а длина данных должна иметь одинаковый размер. Команда MOV может также передавать значения из памяти, например,
MOV AX, ACCT_NUMBER
Здесь ACCT_NUMBER - имя переменной, которую создал программист, как в языке высокого уровня. Переменная создается оператором вида
ACCT_NUMBER DW 0
Этот оператор оставляет место для слова (двух байтов), присваивая им значение 0. Другие допустимые символы в этом операторе это DD - для двойного слова и DB - для байта или строк. Ассемблер следит за адресами переменных, поэтому при ассемблировании оператора
MOV AX, ACCT_NUMBER
имя переменной заменяется ее адресом.
Работа с именами переменных - самый простой способ идентификации данных в программах на языке ассемблера. Но имеются различные способы адресации, которые позволяют программе хранить массивы или использовать указатели. Например,
MOV AX, [BX+SI]
пересылает в AX значение, которое содержится по смещению, равному сумме значений регистров BX и SI.
Процессор 8086 является процессором с сегментной организацией памяти. Он позволяет адресовать 1 Мбайт памяти. Так как все регистры - указатели процессора 8086 (BX, SP, BP, SI, DI и IP) имеют 16 бит, то прямой доступ имеют только 64 Кбайта памяти. Эти 64 Кбайта памяти называются сегментом. Для того чтобы адресовать 1 Мбайт памяти, требуется 20-битовый адрес. Поэтому для представления 20-битового адреса используется два регистра (32 бита). Один регистр содержит адрес сегмента, который задается одним из сегментных регистров (CS, DS, SS или ES). Второй регистр является смещением в сегменте.
Процессор использует четыре сегмента: кода, данных, стека и дополнительный. Сегмент кода содержит код программы, сегмент данных - данные программы, сегмент стека - стек программы, а дополнительный сегмент является дополнительной рабочей памятью программы. Полный 20-битовый адрес, адресующий все адресное пространство процессора, вычисляется следующим образом: значение сегментного регистра сдвигается влево на четыре бита (на одну шестнадцатеричную цифру) и к полученному значению прибавляется смещение. Например, если сегментный регистр содержит значение10FA, а смещение равно 1C2, то физический адрес памяти получается по следующей схеме:
Сегментный регистр: 0001 0000 1111 1010 = 10FA
Сегментный регистр
после сдвига: 0001 0000 1111 1010 0000 = 10FA0
Смещение: 0000 0001 1100 0010 = 01C2
Физический адрес: 0001 0001 0001 0110 0010 = 11162
Как видно из примера, начальный адрес сегмента всегда является 20-битовым числом, а так как сегментный регистр имеет только 16 бит, не достающие младшие 4 бита всегда подразумеваются равными нулю. Это означает, что сегменты всегда начинаются на границе параграфа (отрезок памяти в 16 байт называется параграфом).
Адрес памяти представляется в форме “сегмент: смещение”, поэтому рассмотренный в примере адрес задается в виде 10FA:01C2 .
Сегменты могут быть смежными, разделенными, перекрываться полностью или частично. Так как сегменты могут перекрываться, то она и та же ячейка памяти может содержаться во многих сегментах. Это означает, что она может быть адресована более чем одним адресом. Например, следующие адреса указывают на один и тот же байт памяти:
10FA:01C2 10F0:0262 10E0:0362 10A0:0762
Среди ассемблерных команд есть команды загрузки сегментных и относительных адресов переменных.
MOV AX, SEG ACCT_NUMB
помещает значение сегментного регистра, в котором расположен ACCT_NUMB в AX, а впоследствии это значение будет переслано в DS.
MOV BX, OFFSET ACCT_NUMBER
помещает в BX смещение переменной ACCT_NUMBER в сегменте данных. После выполнения этих команд регистры DS:BX будут указывать на ACCT_NUMBER. Если ACCT_NUMBER является одномерным массивом, то для указания на определенный элемент массива может использоваться добавочное смещение. Команда LEA использует другой способ загрузки смещения.
LEA BX, ACCT_NUMBER
Кодовый сегмент содержит последовательность машинных команд, составляющих программу. Например, команда MOV существует в виде нескольких байтов машинного кода, значение байтов которого определяет в какой регистр идет пересылка и откуда. Регистр IP (счетчик команд) содержит величину смещения, которая указывает на ту команду в кодовом сегменте, которая сейчас должна выполняться. После выполнения команды IP увеличивается таким образом, чтобы он указывал на следующую команду. В простейшей программе счетчик команд будет передвигаться от первого байта кодового сегмента к последнему байту, где программа и завершится. Но, как и другие программы, программа на языке ассемблера может быть разбита на процедуры (подпрограммы), поэтому счетчик команд может прыгать из одного места кодового сегмента в другое.
Когда счетчик команд переходит в другое место кодового сегмента, то его старое значение должно быть запомнено, с тем чтобы можно было вернуться в нужное место, так как это делает оператор RETURN в Бейсике, возвращая управление в то место, откуда была вызвана процедура. В ассемблере процедуре присваивается имя, например, COMBINE_DATA, и оператор CALL СOMBINE_DATA передает управление в процедуру. Процедура завершается командой RET (возврат). При вызове процедуры процессор запоминает текущее значение счетчика команд, записывая в стек. Стек - это область, используемая для временного хранения данных. После завершения процедуры старое значение счетчика команд берется из стека и выполнение программы продолжается. Стек также содержится в отдельном сегменте, который, совершенно естественно, называется сегментом стека. Ему соответствует сегментный регистр SS. В регистре SP хранится указатель стека, который всегда указывает на вершину стека и изменяется при засылке в стек и выборке из стека.
На первый взгляд стек кажется достаточно неуклюжим способом хранения информации, но у него есть два преимущества. Во-первых, доступ к его содержимому намного быстрее, чем к переменным, хранящимся в памяти. Во-вторых, стек может использоваться для многих целей. Он может хранить адреса возврата из процедуры, вложенной в другую процедуру. Впоследствии, то же самое пространство может использоваться программистом для хранения данных, которые должны сейчас обрабатываться, но для которых не хватает места в регистрах микропроцессора. Программа выталкивает содержимое регистра в стек командой PUSH, а позднее забирает его оттуда командой POP. Неправильный порядок обмена данными со стеком - источник многочисленных ошибок при программировании на ассемблере.
После того как программист на ассемблере установил три сегментных регистра (CS, DS и SS) и загрузил данные в регистры микропроцессора он имеет широкий набор команд, которые приведены в приложении.
Язык ассемблера обеспечивает несколько вариантов этих команд. Имеется также целый класс команд, называемых псевдооператорами, которые помещаются в текст программы с целью указания ассемблеру как обрабатывать данную программу. Например, один из типов псевдооператоров автоматически вставляет часто используемый кусок кода по всей программе. Такая порция кода называется макросом и именно это свойство ассемблера дало ему название “макроассемблер”.