Арифметичні та логічні операції мови асемблер мікропроцесора Intel8086
Команда перенесення даних У чотирирозрядних та вісьмирозрядних процесорах існувало багато асемблерних кодів для команд перенесення даних. Наприклад, існували окремі команди для перенесення даних з одного регістру процесора до іншого, з комірки пам’яті до регістру та з регістру до комірки пам’яті. Але перехід до шістнадцятирозрядної шини даних дозволив реалізувати один асемблерний код команди MOV… Читати ще >
Арифметичні та логічні операції мови асемблер мікропроцесора Intel8086 (реферат, курсова, диплом, контрольна)
ТЕМА РОБОТИ
Арифметичні та логічні операції мови асемблер мікропроцесора Intel8086
МЕТА РОБОТИ: Навчитися писати на мові асемблер прості програми, які реалізують алгоритми, що містять арифметичні та логічні операції над чисельними даними.
ТЕОРЕТИЧНІ ВІДОМОСТІ
Директиви визначення даних
Для безпосереднього визначення чисельних та рядкових величин, які не змінюються при виконанні програми, у мові асемблер введені директиви визначення даних. Формат директиви визначення даних такий:
[ім'я] D{n} {вираз}
де D{n} - одна з команд визначення даних, які будуть наведені нижче. Ім'я елемента вказувати не обов’язково. Але, оскільки у програмі завжди існують посилання на ті чи інші дані, використання імен для роботи з ними є найбільш зручним.
Наприклад:
A1 DW 2; Визначити слово (дві комірки пам’яті) та занести до них число 2.
A2 DB 5; Визначити байт (одну комірки пам’яті) та занести до неї число 5.
MOV AX, A2; Занести число A2 до акумулятора.
MOV CH, A1; Занести число A1 до старших 8 бітів регістру СX.
Існує чотири команди визначення даних, які підтримуються в мові асемблер:
DB — визначити байт (одну комірку пам’яті);
DW — визначити слово (дві комірки пам’яті);
DQ — визначити чотири слова (вісім комірок пам’яті);
DT — визначити десять слів (двадцять комірок пам’яті).
Вирази при описуванні даних можуть бути чотирьох типів.
Вирази-константи. У директивах з виразами-константами чисельні дані задаються безпосередньо, при цьому визначається також їх тип. Подальше у програмі вони можуть бути використані тільки як дані визначеного типу. Крім того, після числа вказується система числення, у якій записано число:
B — двійкова;
Q — вісімкова;
H — шістнадцятирічна;
D — десяткова.
Якщо, як у попередньому прикладі, явних вказівок на систему числення немає, то по замовченню число розглядається як десяткове.
Наприклад:
A1 DW 2; Визначити слово (дві комірки пам’яті) та занести до них число 2.
A2 DB 15H; Визначити байт (одну комірки пам’яті) та занести до неї
; шістнадцятирічне число 15.
B1 DQ 17Q; Визначити чотири слова та занести до них вісімкове число 17.
Завдання для перевірки № 1. Переведіть числа, які позначені змінними A2 та B1 у двійкову та у десяткову системи числення.
Слід зазначити, що у мові асемблера процесора Intel 8086 передбачені переміщення та обробку лише даних одного типу. Наприклад, запис:
A2 DB 15H
MOV AX, A2
є невірним, тому що до акумулятора, якій має 16 розрядів, ми намагаємося завантажити восьмирозрядне число (1 байт). Нижче наведено 2 вірних варіанти:
A2 DB 15H
MOV AL, A2 A2 DW 15H
MOV AX, A2
2. Невизначені вирази. Якщо комірка пам’яті мусить бути завантажена не з початку роботи програми, а тільки у процесі її роботи, то її перед початком роботи програми треба зарезервувати. Це досягається таким чином:
A1 DW ?;
Тоді у будь-якому місті програми можна поставити оператор типу:
MOV A1, АX
Результатом виконання такого оператора буде перенесення даних з акумулятора до комірки пам’яті з ім'ям A1. Як вам відомо, у мовах високого рівня, таких як ПАСКАЛЬ, С або ж Фортран, таке визначення змінних також ефективно використовується, а самі такі змінні називають невизначеними або динамічними.
Завдання для перевірки № 2. Пригадайте, як визначаються динамічні змінні у мові програмування ПАСКАЛЬ? В яких випадках вони використовуються
3. Вирази з визначенням кількох констант. Вираз може містити водночас декілька констант, що розділяються комами. Кількість таких констант обмежується тільки довжиною рядка. Наприклад:
A3 DB 10,12,23H, 1001B
асемблер визначає такі константи у вигляді послідовних суміжних байт. Посилання на ім'я А3 вказує на першу константу, А3+1 — на другу, А3+2 — на третю тощо. Наприклад, команда:
MOV AH, A3+2
заносить до старших восьми розрядів акумулятора шістнадцятирічне число 23.
При роботі з константами такого типу треба мати на увазі, що якщо команда асемблера DB резервує по одному байту для кожного числа, то команда DW — по одному слову (два байти), незалежно від кількості розрядів у числах, що завантажуються. Тому при використанні команди типу
A3 DW 10,12,23H, 1001B
посилання на другу константу (число 12) буде здійснюватись через вираз А3+2, а не А3+1, як це було у попередньому прикладі (поясніть чому саме). У мовах високого рівня таким чином описуються змінні з індексами або масиви.
Завдання для перевірки № 3. Скільки констант визначено в наведеному вище операторі DB під назвою А3? Переведіть всі ці числа у двійкову, десяткову та шістнадцятирічну системи числення. Як би ви визначили відповідний масив з ім'ям А3 у мові програмування ПАСКАЛЬ?
Завдання для перевірки № 4: Напишіть на мові асемблера фрагмент програми, у якому:
Завантажте п’ять чисел: 12,13H, 18,70Q, 280 під одним ім'ям.
Завантажте друге з визначених чисел до регістру АХ, а п’яте до регістру СХ.
Яку з наведених вище команд ви використали для визначення даних і чому?
4. Вирази з повторенням змінних. Директиви визначення даних допускають заповнення сусідніх комірок пам’яті однаковими значеннями через дублювання даних. Формат такої директиви має вигляд:
[ім'я] D{n} {число повторень} DUP {вираз}
Наприклад:
DW 10 DUP (?); Десять невизначених слів.
DB 5 DUP (14); П’ять байт, в яких містяться числа 0EH.
DB 3 DUP (4DUP (8)); Дванадцять байт, в яких містяться числа 8H.
Завдання для перевірки № 5. Наведіть свої приклади виразів з повторенням змінних та поясніть їх викладачеві. Які ви бачите можливості практичного використання виразів з повторенням змінних при написані програм?
Вираз може містити чисельну або символьну константу. Символьні константи беруться у подвійні або одинарні `лапки' та переводяться при обробці програми в коди ASCII. Наприклад:
A1 DB `IBM PC AT'
Більш досконало робота з рядковими константами у мові програмування асемблер буде описана у теоретичних відомостях до лабораторної роботи № 4.
Команда перенесення даних У чотирирозрядних та вісьмирозрядних процесорах існувало багато асемблерних кодів для команд перенесення даних. Наприклад, існували окремі команди для перенесення даних з одного регістру процесора до іншого, з комірки пам’яті до регістру та з регістру до комірки пам’яті. Але перехід до шістнадцятирозрядної шини даних дозволив реалізувати один асемблерний код команди MOV для будь-якої операції перенесення даних.
Формат команди:
{позначка} [код команди] [операнд-приймач], [операнд-джерело]
Увага! Розташування в цій команді приймача і джерела даних є стандартним для процесорів фірми Intel.
Використання команди MOV тісно пов’язано з видами адресації, що використовуються в асемблері.
Відрізняють п’ять головних видів адресації.
1. Безпосередня адресація.
Дані, що завантажуються, містяться безпосередньо у коді команди.
Наприклад
A4 DB ?; Зарезервувати комірку для змінної А4.
…
MOV AX, 15H; Завантажити до акумулятора число 15H.
MOV A4,15H; Завантажити до комірки пам’яті A4 число 15H.
2. Неявна адресація. Джерело та приймач інформації записуються у самому коді команди.
Це може бути назва регістру або посилання на комірку пам’яті.
Наприклад:
A1 DB 100H; Завантажити до комірки пам’яті A1 число 100H.
…
MOV BX, A1; Завантажити до регістру BX вміст комірки A1.
MOV AX, BX; Завантажити до регістру AX вміст регістру BX.
3. Пряма адресація. Безпосереднє звертання до комірки пам’яті з визначеним номером. Цей вид адресації використовується при системному програмуванні для занесення даних до комірок пам’яті, вміст яких впливає на виконання системних процедур та загалом на представлення інформації в комп’ютері. Наприклад:
MOV [B8000], `A'; Завантажити символ, А до відеопам'яті.
При вирішенні несистемних математичних та логічних задач цим видом адресації програмісти майже не користуються. Замість нього в більшості випадків використовується безпосередня та неявна адресація.
4. Посередня адресація. При цьому виді адресації вміст одного регістру або регістрової пари процесора є вказівником на комірку пам’яті, що містить потрібну інформацію або в яку вона мусить бути поміщена. Посилання на поточну комірку пам’яті позначається символом $ (долар). Наприклад:
MOV BX, 100H
МOV CX, [BX];
Завантажити до регістру СХ число з сегменту даних зі зміщенням 100Н (повна адреса комірки пам’яті DS:100H).
Як можна побачити з наведеного прикладу, посилання на комірку пам’яті позначається в асемблері через квадратні дужки.
5. Адресація зі зміщенням. Як і посередня адресація, місить посилання на комірку пам’яті. Зміщення вказується як безпосередній операнд. Ефективно використовується разом з директивою визначення кількох констант.
Наприклад:
A DB 1,2,3,4,5; Визначення масиву з кількох констант.
…
MOV BX, A+3; Завантажити до регістру BX число 3.
Арифметичні операції над двійковими числами Додавання та віднімання байт або слів, що містять двійкові дані, здійснюється за допомогою команд ADD та SUB відповідно [1,4,7−9].
Формат команд додавання та віднімання у мові програмування асемблер цілком співпадає з форматом команди MOV:
{позначка} [код команди] [операнд-приймач], [операнд-джерело]
Зрозуміло, що результат операції буде завантажений до операнда-приймача. Таким чином, наприклад, при складанні двох чисел (виконанні команди ADD), перше з чисел, які складаються, буде втрачене, а замість нього у відповідний регістр або комірку пам’яті завантажується отриманий результат.
Віднімання у двійковій арифметиці реалізується через додавання від'ємних чисел. Від'ємне число містить одиничний біт у старшому розряді та формуються за допомогою двійкового доповнення. Таким чином, для представлення від'ємного числа необхідно інвертувати всі біти додатного числа та до отриманого результату додати одиницю.
Наприклад
Число 65 | |||
Інверсія бітів | |||
Додати 1 | Число -65 | ||
Зміна знака від'ємного числа проводиться таким самим чином: треба інвертувати всі біти додатного числа та до отриманого результату додати одиницю. Для нашого прикладу:
Число -65 | |||
Інверсія бітів | |||
Додати 1 | Число 65 | ||
Сума двох рівних за модулем, але різних за знаком чисел, при такому формуванні кодів від'ємних чисел завжди буде дорівнювати 0 (перевірте це для чисел 65 та -65 та спробуйте математично довести цю тотожність).
Таким чином, процесор записує від'ємні числа як великі додатні, і правила мови асемблера не дають можливостей їх відрізнити. Програміст повинен сам чітко слідкувати за зміною чисел у регістрах і фіксувати їх знак, якщо у цьому є необхідність.
Існують п’ять можливих ситуацій використання команд ADD та SUB, що пов’язані з представленням та розташуванням даних, які представлені у таблиці 1.
асемблерний двійковий число адресація Таблиця 1 — Команди додавання та віднімання мови АСЕМБЛЕР
Операція | Приклади | |
Додавання або віднімання регістр-регістр | ADD AX, BX SUB CL, DL | |
Додавання або віднімання регістр-пам'ять | A1 DW 50H A2 DB 10H … ADD AX, A1 SUB CL, A2 | |
Додавання або віднімання пам’ять-регістр | A1 DW 50H A2 DB 10H … ADD A1, AX SUB A2, CL | |
Додавання або віднімання регістр-безпосереднє значення | ADD A1,10H SUB A2,8 | |
Додавання або віднімання пам’ять-безпосереднє значення | A1 DW 50H A2 DB 10H … ADD A1,5 SUB A2,12H | |
Прямої операції «Пам'ять-Пам'ять» мікропроцесори типу Intel 80×86 не підтримують. Тому такі дії потрібно здійснювати через три елементарних операції процесора:
1. Занесення даних з комірки пам’яті № 1 до регістру.
2. Виконання операції додавання або віднімання між регістром та коміркою пам’яті № 2.
3. Занесення даних з регістру до комірки пам’яті № 2.
Наприклад:
A1 DW 50H
A2 DW 10H
…
MOV AX, A1
ADD AX, A2
MOV A2, AX
Множення та ділення чисельних даних у мові асемблер здійснюється за допомогою команд MUL та DIV для беззнакових чисел та за допомогою команд IMUL та IDIV для знакових чисел. Контроль над форматом чисел, що обробляються, не може здійснюватись процесором автоматично, тому вибирати для використання ту чи іншу команду повинен сам програміст.
В асемблері мікропроцесора Intel 8086 існують два формати команди множення — множення байта на байт та множення слова на слово. При множенні байта на байт один з множників знаходиться у регістрі AL, а другий — в байті пам’яті або в однобайтовому регістрі. Результат виконання операції множення буде розміщений в регістрі AX.
Наприклад, фрагмент програми, що знаходить куб числа 5, можна записати таким чином:
A1 DB 5H
…
MOV AL, A1
MUL A1
MUL A1
При множенні слова на слово один з множників знаходиться у регістрі AX, а другий — в двох байтах пам’яті або в одному з регістрів процесора. Результатом множення в цьому випадку буде подвійне слово. Його молодші розряди будуть розташовані в регістрі AX, а старші - в регістрі DX. Треба мати на увазі, що ця команда ігнорує (затирає) будь-які дані, що містяться в регістрі DX. Наприклад, фрагмент програми, яка підносить число 100H до кубу можна записати так:
A1 DW 100H
…
MOV AX, A1
MUL A1
MUL A1
Таким чином, формат команд множення у мові програмування асемблер такий:
{позначка} [код команди] [операнд]
Операнд команди множення визначає розташування першого множника та його формат (байт або слово). Другий множник, відповідно до логіки роботи команди, мусить бути розташований в акумуляторі.
Завдання для перевірки № 6. За якими ознаками процесор визначає, що в першому випадку треба множити байти, а в другому — слова?
Команда множення IMUL працює цілком аналогічним чином, з урахуванням знаку числа.
Наприклад:
A1 DB 1 011 0111B
…
MOV AL, 5
MUL A1
…
MOV AL, 5
IMUL A1
Оскільки останній біт числа A1 дорівнює одиниці, то в першому випадку воно буде розглядатися як велике додатне, а в другому — як від'ємне число.
Завдання для перевірки № 7. Підрахуйте без використання калькулятора, який результат буде отриманий в першому та другому випадках.
Команда ділення в асеблері також має два формати: ділення слова на байт та ділення подвійного слова на слово. При діленні слова на байт ділене міститься в регістрі AX, а дільник — у байті пам’яті або в однобайтовому регістрі. При діленні слова на байт результат ділення буде розміщений таким чином: частка — у регістрі AH, а остача — у регістрі AL. При діленні подвійного слова на слово ділене знаходиться в парі регістрів DX: AX, а дільник — у регістрі або в слові пам’яті. Після операції ділення остача завантажується в регістр DX, а частка в регістр AX. Команда DIV використовується для беззнакових, а IDIV — для знакових даних.
Таким чином, формат команд множення мові програмування асемблер повністю відповідає формату команди множення:
{позначка} [код команди] [операнд]
Команди логічних операцій Як відомо, логічні операції є важливим елементом у проектуванні цифрових електронних схем. Але двійкова логіка має також багато спільного із логікою програмування. Наприклад, всі арифметичні операції здійснюються на апаратному рівні як послідовність великого числа логічних операцій [1,4]. Крім того, команди логічних операцій знаходять широке використання для моделювання логіки роботи цифрових схем, для здійснення арифметичних операцій з кодами ASCII, для накладення масок (виділення окремих біт числа), а також для організування логіки програми. В мові програмування асемблер підтримується шість головних команд для виконання логічних операцій: AND, OR, XOR, NOT та TEST.
Ці команди обробляють один байт або одне слово в регістрі або в комірці пам’яті. Встановлюють прапори: CF (прапор переносу), OF (прапор переповнення), PF (прапор парності), SF (прапор знаку), ZF (прапор нуля). Працюють команди логічних операцій наступним чином:
AND — якщо обидва біта, що зрівнюються, дорівнюють 1, то результат дорівнює 1, а в іншому випадку 0 (команду AND називають також логічним множенням).
OR — якщо хоча б один з бітів, що зрівнюється, дорівнює 1, то результат теж дорівнює 1, а в іншому випадку 0 (команду OR називають також логічним діленням).
XOR — якщо біти, що зрівнюються, співпадають, то результат дорівнює 0, а якщо різняться — 1.
NOT — команда має один операнд та здійснює інверсію всіх бітів числа.
TEST — працює як команда AND, але тільки змінює прапори стану, не впливаючи на результат. Може бути використана для перевірки окремих байтів числа на наявність одиниць.
Приклади виконання логічних команд наведені в табл. 2:
Таблиця 2 — Приклади виконання логічних команд
Команда | AND | OR | XOR | NOT | |
Перше число | |||||
Друге число | ; | ||||
Результат | |||||
Формат логічних команд такий же самий, як і арифметичних:
{позначка} [код команди] [операнд-приймач], [операнд-джерело]
Завдання для перевірки № 8. Наведіть свої приклади логічних команд. Напишіть на мові асемблера фрагмент програми, який містить логічні команди, та визначте, яким буде результат виконання цього фрагменту програми. Результат роботи покажіть викладачеві.
Команди зсуву бітів числа У мові асемблер є чотири команди зсуву бітів — SAR, SAL, SHR та SHL. Зсув можна виконати праворуч або ліворуч на 8 позицій для байта або на 16 для слова.
Команда містить два операнди: перший з них — регістр або комірка пам’яті, де розміщено байт або слово, які потрібно обробити, а другий — вказівник на кількість позицій зсуву. Зсув на одну позицію можна вказати безпосередньо, а для зсуву на дві позиції або більше треба вказати кількість позицій у регістрі CL.
Отже, формат команд зсуву в мові програмування асемблер такий:
{позначка} [код команди] [операнд1], [операнд2]
Команда SAR — арифметичний зсув праворуч.
Команда SAL — арифметичний зсув ліворуч.
Команда SHR — логічний зсув праворуч.
Команда SHL — логічний зсув ліворуч.
Наприклад:
MOV CL, 3
MOV AX, 1 011 0111B
SHR AX, 1
SHR AX, CL
Команди циклічного зсуву бітів числа Циклічний зсув, на відміну від логічного та арифметичного, передбачає перенесення біта, що зсувається, до розряду, який при цьому звільняється. У мові асемблер є чотири команди циклічного зсуву:
ROR — циклічний зсув праворуч;
ROL — циклічний зсув ліворуч;
RCR — циклічний зсув праворуч з урахуванням перенесення;
RCL — циклічний зсув ліворуч з урахуванням перенесення.
Роботу команд циклічного зсуву на одну позицію відображено на рисунку 1.
ROL
RCL
RCR
Рисунок 1 — Ілюстрація виконання команд циклічного зсуву Структура асемблерних програм для COMта EXE-модулів. Виклик процедур. Стек Зрозуміло, що процесор «не розуміє» асемблерних команд. Їх потрібно перевести у чисельні двійкові комп’ютерні коди. Програма на мові асемблера називається початковою, а програма у комп’ютерних кодах об'єктною.
Переведення початкового коду до об'єктного здійснює програма TASM. Можна виконати і зворотню операцію — перевести об'єктний код до початкового, проаналізувати і навіть змінити його за допомогою відладчиків TASM та AFD. Саме ці операції були предметом вивчення у першій лабораторній роботі.
Як вже було відмічено, загалом будь-яка програма містить три пов’язані між собою блоки: сегмент коду, сегмент стеку та сегмент даних. При програмуванні на асемблері до сегмента коду входять коди команд обробки даних, а до сегмента даних — директиви їх визначення. Стек — це окрема область пам’яті, яка відрізняється особливістю організації доступу. Якщо до стека завантажено декілька чисел, то зчитати можна лише число, яке було завантажене останнім. Тобто, якщо до стека послідовно завантажено чотири числа, для того, щоб зчитати друге, потрібно з початку зчитати четверте та третє. Кількість завантажених байтів для процесора Intel 8086 та сумісних з ним визначається через вказівник стеку SP, а адреса сегмента стека — значенням регістру SS. У літературі стекова організація пам’яті отримала також назву «останній зайшов — перший вийшов».
Зрозуміло, що така організація пам’яті не є зручною для завантаження даних користувача, які можуть стати потрібними у будь-який момент у будь-якому порядку. Але саме вона допомагає організувати ефективну обробку зовнішніх функцій та процедур. Виконання команди виклику процедури CALL процесор здійснює таким чином:
адреса, що міститься в командному вказівнику, завантажується до стеку. При цьому вказівник стеку збільшується на 2;
вміст всіх регістрів процесора також завантажується до стеку, проводиться відповідна зміна вказівника стеку;
здійснюється передача керування за адресою початку процедури.
Кожна процедура завершується командою RET, яка зменшує вказівник стеку на відповідну величину і завантажує числа, які в ньому містилися, до командного вказівника та регістрів процесора. Така організація обробки процедур є дуже ефективною і дозволяє уникнути помилок при зміні та відновленні адрес та зберегти всі дані користувача при ефективній організації обчислень.
Але у деяких випадках стек може бути використаний і безпосередньо для зберігання даних. Для цього призначені такі головні асемблерні команди:
PUSH — завантажити до стеку одне слово. Команда має лише один операнд, яким можуть виступати регістр загального призначення, комірки пам’яті, сегментні регістри. Вказівник стеку після виконання команди збільшується на 2.
POP — вивантажити слова із стека. Команда також має один операнд, який завжди є ідентичним до операнду попередньої команди PUSH. Вказівник стеку після виконання команди зменшується на 2.
PUSHA — команда заносить до стеку одночасно вісім значень, що містяться відповідно в регістрах AX, BX, CX, DX, SP, BP, SI, DI. Вказівник стеку збільшується на 16. Після цієї команди одночасне відновлення всіх значень регістрів може бути здійснено через команду POPA.
PUSHF — заносить до стеку слово стану процесора. Для відновлення регістру стану достатньо виконати команду POPF.
Формат команд PUSH та POP:
{позначка} [код команди] [операнд]
Команди PUSHA, POPA, PUSHF та POPF не містять операндів.
Як вам відомо з курсу «Персональні комп’ютери та мови програмування», існує 2 типи об'єктних файлів — модулі типу exe та модулі типу com. Написання мовою асемблера модулів цих типів має свої особливості.
Особливості написання модуля типу com:
Обсяг com-програми не повинен перевищувати розміру одного сегмента (64К). Тому дані користувача об'єднуються з кодами команд, а стек, якщо в цьому є необхідність, генерується автоматично.
Будь-яка програма, що працює під керуванням MS-DOS, починається з префікса програмного сегмента (PSP), який займає 256 перших байт будь-якого сегмента. PSP створюється автоматично при завантаженні програми системою (дивиться рис. 2). Але в com-програмі PSP не виконується, тому першим оператором будь-якої com-програми мусить бути директива ORG 100H (перехід на початок програми користувача).
Оскільки директиви визначення даних містяться у тому ж сегменті, що і команди програми, але не виконуються комп’ютером при її обробці, для коректного виконання програми треба обходити місце визначення даних за допомогою команди безумовного переходу JMP. Будь-яка com-програма закінчується командою RET, яка повертає керування до операційної системи MS-DOS.
Таким чином, структура com-програми повинна бути такою:
ORG 100H; Перехід на початок програми користувача.
JMP START; Перехід на частину програми, яка виконується.
A1 DB 25H; Область визначення даних.
…
START: MOV AX, A1; Область команд програми.
…
RET; Передача керування до MS-DOS.
Особливості написання та створення модуля типу exe:
Обов’язкове визначення всіх трьох сегментів — коду, стеку та даних.
Обов’язкова ініциалізація сегментних регістрів через директиву ASSUME.
На початку exe-модуля, що завантажений до пам’яті, стоїть PSP, який їм використовується. Програма автоматичного завантаження MS-DOS використовує регістр DS для встановлення початкової адреси PSP. Тому у програмі користувача треба насамперед зберегти цю адресу, завантаживши її до стеку. Після закінчення програми це значення буде використане командою RET для повернення до MS-DOS.
Для операційної системи потрібно, щоб наступне значення стеку було нульовим. Для цього необхідно за допомогою команди SUB почистити регістр AX та завантажити до стеку нульове значення.
Програма завантаження встановлює вірні адреси сегментів коду та стеку. Але ж регістр сегменту даних DS використовується нею для інших цілей і має після її виконання невірне значення. Тому треба перезавантажити регістр DS за допомогою двох команд MOV.
exe-програма завжди повинна мати модульну структуру. Тому всі частини програми, включаючи головну, реалізуються як процедури.
Таким чином, структура коректно написаної exe-програми така:
STACKSG SEGMENT PARA STACK 'Stack'
DW 32 DUP (?); Визначення стеку.
STACKSG ENDS
DATASG SEGMENT PARA 'Data'
…
DATASG ENDS
CODESG SEGMENT PARA 'Code'
BEGIN PROC FAR
ASSUME CS: CODESG, DS: DATASG, SS: STACKSG, ES: DATASG
PUSH DS;
SUB AX, AX;
PUSH AX;
MOV AX, DATASG ;
MOV DS, AX;
…
RET
BEGIN ENDP
CODESG ENDS
END BEGIN
Завдання:
1. Визначити дані:
А110; a215; b140; b225; c15; c26.
2. Занести в регістри AX, BX, CX та DX процесора такі величини:
AXа1-a2; BXb1*b2; CXc1+c2; DX
ВИКОНАННЯ РОБОТИ
Текст програми приведений в таблиці 3.
Таблиця 3 — Текст програми з коментарями
Початковий код асемблерної програми | Машинні коди | Коментарі | |
Org 100h | ; | Директива, яка вказує асемблеру адресу початку програми в сегменті коду | |
mov ax, b1 | A1 2B 01 | Завантажити до регістру ax змінну b1, розташовану за адресою 012Bh. Адреса комірки у машинних кодах розташовуються у зворотному порядку. Після виконання команди ax = 0028h. Інші регістри загального призначення залишаться без змін. | |
imul b2 | F7 2E 2D 01 | Помножити регістр ах на змінну b2, розташовану за адресою 012Dh як числа зі знаком. Адреса комірки у машинних кодах розташовуються у зворотному порядку. Після виконання команди ax = 03E8h, DX=0000h. Прапори регістра стану не змінилися. Інші регістри загального призначення залишаться без змін. | |
mov bx, ax | 2B D8 | Перенесення значення регістра ax в регістр bx. Після виконання команди bx=03E8h. Інші регістри загального призначення залишаться без змін. | |
mov ax, a1 | A1 27 01 | Завантажити до регістру ax змінну a1, розташовану за адресою 0127h. Адреса комірки у машинних кодах розташовуються у зворотному порядку. Після виконання команди ax = 000Ah. Інші регістри загального призначення залишаться без змін. | |
sub ax, a2 | 2B 06 29 01 | Віднімання від ах змінної а2. Різниця записується в регістр ax. Після виконання команди ах=fffbh. Після віднімання в регістрі прапорів будуть встановлені прапори займу CF, знаку SF, та прапор AF. Інші регістри загального призначення залишаться без змін. | |
mov cx, c1 | 8B 0E 2 °F 01 | Завантажити до регістру ax змінну с1, розташовану за адресою 012Fh. Адреса комірки у машинних кодах розташовуються у зворотному порядку. Після виконання команди cx = 0005h. Інші регістри загального призначення залишаться без змін. | |
add cx, c2 | 03 0E 31 01 | Підсумовування регістру сx і змінної с2. Сума записується в регістр сx. Після виконання команди сx=000Bh. Після складання в регістрі прапорів будуть скинуті прапори займу CF, знаку SF, та прапор AF. Інші регістри загального призначення залишаться без змін. | |
mov dx, c1 | 2B 16 2 °F 01 | Завантажити до регістру dx змінну с1, розташовану за адресою 012Fh. Адреса комірки у машинних кодах розташовуються у зворотному порядку. Після виконання команди dx = 0005h. Інші регістри загального призначення залишаться без змін. | |
and dx, a2 | 23 16 29 01 | Логічна операція І регістра dx і змінної a2. Результат записується в регістр dx. Після виконання команди dx=0005h. Після операції в регістрі прапорів буде встановлений прапор парності PF. Інші регістри загального призначення залишаться без змін. | |
xor dx, a1 | 33 16 27 01 | Логічна операція ВИКЛЮЧНЕ АБО регістра dx і змінної a1. Результат записується в регістр dx. Після виконання команди dx=000Fh. Після операції в регістрі прапорів буде встановлений прапор парності PF. Інші регістри загального призначення залишаться без змін. | |
not dx | F7 D2 | Логічна унарна операція НІ регістра dx. Результат записується в регістр dx. Після виконання команди dx=fff0h. Після операції в регістрі прапорів буде встановлений прапор парності PF. Інші регістри загального призначення залишаться без змін. | |
ret | C3 | Закінчення програми. | |
a1 DW 10 | 0A 00 | Змінні, які використовуються | |
a2 DW 15 | 0 °F 00 | у програмі. | |
b1 DW 40 | 28 00 | У пам’яті розташовані таким чином, що | |
b2 DW 25 | 19 00 | молодший байт розташовано за молодшою | |
c1 DW 5 | 05 00 | адресою (стандарт (INTEL). | |
c2 DW 6 | 06 00 | ||
ВИСНОВОК
В ході виконання лабораторної роботи навчилися писати на мові асемблер прості програми, які реалізують алгоритми, що містять арифметичні та логічні операції над чисельними даними.
Чисельні дані та адреси розташовуються у пам’яті за стандартом INTEL — молодший байт розташовано за молодшою адресою.