Системне програмування, доц. І.І. Мітасов, 2010р. Лекція 3, 5 сторінок
Тема 1. Архітектура процесора і мова асемблера: Апаратне і програмне забезпечення соі
Лекція 3. Машинний рівень програмування
Питання лекції:
Структура машинної команди;
Способи завдання операндів команди.
1. Структура машинної команди
Машинна команда є закодованою по певних правилах вказівкою мікропроцесору на виконання деякої операції або дії. Кожна команда містить елементи, що визначають:
що робити? (відповідь на це питання дає елемент команди, званий кодом операції (КОП));
об'єкти, над якими потрібно щось робити (ці елементи називаються операндами);
як робити? (ці елементи називаються типами операндів — зазвичай задаються неявно).
Приведений на рис. 3.1 формат машинної команди є найзагальнішим. Максимальна довжина машинної команди — 15 байт. Реальна команда може містити набагато меншу кількість полів, аж до одного — лише КОП.
Рис. 3.1 – Формат машинної команди
Опишемо призначення полів машинної команди.
Префікси. Необов’язкові елементи машинної команди, кожен з яких складається з одного байта або може бути відсутнім. У пам'яті префікси передують команді. Призначення префіксів — модифікувати операцію, що виконується командою. Прикладна програма може використовувати наступні типи префіксів:
Префікс заміни сегменту. У явній формі вказує, який сегментний регістр використовується в даній команді для адресації стека або даних. Префікс відміняє вибір сегментного регістра за умовчанням. Префікси заміни сегменту мають наступні значення:
2eh
— заміна
сегменту
cs;
36h
— заміна
сегменту
ss;
3eh
— заміна
сегменту
ds;
26h
— заміна
сегменту
es;
64h
— заміна
сегменту
fs;
65h
— заміна
сегменту
gs.
Префікс розрядності адреси уточнює розрядність адреси (32 або 16-розрядна). Кожній команді, в якій використовується адресний операнд, ставиться у відповідність розрядність адреси цього операнда. Ця адреса може мати розрядність 16 або 32 біт. Якщо розрядність адреси для даної команди 16 біт, це означає що команда містить 16-розрядне зміщення (див. рис. 3.2), воно відповідає 16-разрядному зміщенню адресного операнда відносно початку деякого сегменту. У контексті рис. 3.2 це зміщення називається ефективною адресою. Якщо розрядність адреси 32 біт, це означає, що команда містить 32-розрядне зміщення (див. рис. 3.1), воно відповідає 32-розрядному зміщенню адресного операнда відносно початку сегменту і по його значенню формується 32-бітне зміщення в сегменті. За допомогою префікса розрядності адреси можна змінити значення розрядності адреси, що діє за умовчанням. Ця зміна стосуватиметься лише тієї команди, якій передує префікс.
Префікс розрядності операнда аналогічний префіксу розрядності адреси, але вказує на розрядність операндів (32 або 16-разрядні), з якими працює команда. Відповідно до яких правил встановлюються значення атрибутів розрядності адреси і операндів за умовчанням? У реальному режимі і режимі віртуального i8086 значення цих атрибутів — 16 біт. У захищеному режимі значення атрибутів залежать від значення біта D в дескрипторах виконуваних сегментів. Якщо D = 0, то значення атрибутів, що діють за умовчанням, дорівнюють 16 біт; якщо D = 1, то 32 біт. Значення префіксів розрядності операнда 66h і розрядності адреси 67h. Ви можете за допомогою префікса розрядності адреси в реальному режимі використовувати 32-розрядну адресацію але при цьому необхідно пам'ятати про обмеженість розміру сегменту величиною 64 Кбайт. Аналогічно префіксу розрядності адреси ви можете використовувати префікс розрядності операнда в реальному режимі для роботи з 32-розрядними операндами (наприклад, в арифметичних командах).
Рис. 3.2 – Механізм формування фізичної адреси в реальному режимі
Префікс повторення використовується з ланцюжковими командами (командами обробки рядків). Цей префікс “зациклює” команду для обробки всіх елементів ланцюжка. Система команд підтримує два типи префіксів:
безумовні (rep — 0f3h), що заставляють повторюватися ланцюжкову команду деяку кількість разів;
умовні (repe/repz — 0f3h, repne/repnz — 0f2h), які при зацикленні перевіряють деякі прапори, і в результаті перевірки можливий достроковий вихід з циклу.
Код операції. Обов'язковий елемент, що описує операцію, котра виконується командою. Багатьом командам відповідає декілька кодів операцій, кожен з яких визначає нюанси виконання операції.
Подальші поля машинної команди визначають місце розташування операндів, що беруть участь в операції, і особливості їх використання. Розгляд цих полів пов'язаний зі способами завдання операндів в машинній команді і тому буде виконано пізніше.
Байт режиму адресації mod-r/m. Значення цього байта визначає використовувану форму адреси операндів. Операнди можуть знаходитися в пам'яті, в одному або двох регістрах. Якщо операнд знаходиться в пам'яті, то байт mod-r/m визначає компоненти (зміщення, базовий та індексний регістри), використовувані для обчислення його ефективної адреси (див. рис. 3.2). У захищеному режимі для визначення місця розташування операнда в пам'яті може додатково використовуватися байт sib (scale-index-base — масштаб-індекс-база). Байт mod-r/m складається з трьох полів:
поле mod визначає кількість байт, зайнятих в команді адресою операнда (див. поле зміщення в команді). Поле mod використовується спільно з полем r/m, яке вказує спосіб модифікації адреси операнда зміщення в команді. Наприклад, якщо mod = 00, це означає, що поле зміщення в команді відсутнє, і адреса операнда визначається вмістом базового та (або) індексного регістра. Які саме регістри використовуватимуться для обчислення ефективної адреси, визначається значенням цього байта. Якщо mod = 01, це означає, що поле зміщення в команді присутнє, займає один байт і модифікується вмістом базового та (або) індексного регістра. Якщо mod = 10, це означає, що поле зміщення в команді присутнє, займає два або чотири байти (залежно від розміру адреси, що діє за умовчанням або визначуваного префіксом) і модифікується вмістом базового та (або) індексного регістра. Якщо mod = 11, це означає, що операндів в пам'яті немає: вони знаходяться в регістрах. Це ж значення байта mod використовується у випадку, коли в команді застосовується безпосередній операнд;
поле reg/коп визначає або регістр, що знаходиться в команді на місці першого операнда, або можливе розширення коду операції;
поле r/m використовується спільно з полем mod і визначає або регістр, що знаходиться в команді на місці першого операнда (якщо mod = 11), або використовувані для обчислення ефективної адреси (спільно з полем зміщення в команді) базові і індексні регістри.
Байт масштаб-індекс-база (байт sib) використовується для розширення можливостей адресації операндів.
На наявність байта sib в машинній команді вказує поєднання одного зі значень 01 або 10 полів mod і значення поля r/m= 100. Байт sib складається з трьох полів:
поле масштабу ss. У цьому полі розміщується масштабний множник для індексного компоненту index, що займає наступні три біта байта sib. У полі ss може міститися одне з наступних значень: 1, 2, 4, 8. При обчисленні ефективної адреси на це значення умножатиметься вміст індексного регістра. Детальніше з практичної точки зору ця розширена можливість індексації розглядається при вирішенні питань роботи з масивами;
поле index — використовується для зберігання номера індексного регістра, який застосовується для обчислення ефективної адреси операнда;
поле base — використовується для зберігання номера базового регістра, який також застосовується для обчислення ефективної адреси операнда. В якості базового та індексного регістрів можуть використовуватися практично всі регістри загального призначення.
Поле зміщення в команді. 8-, 16- або 32-розрядне ціле число зі знаком, що є, повністю або частково (з врахуванням наведених вище міркувань), значенням ефективної адреси операнда.
Поле безпосереднього операнда. Не обвязкове поле, що є 8-, 16- або 32-розрядним безпосереднім операндом. Наявність цього поля, звичайно, відбивається на значенні байта modr/m.
2. Способи завдання операндів команди
В ході попереднього викладу ми мимоволі торкалися питання про те, де розташовуються операнди, з якими працює машинна команда, і як це відбивається на вмісті її полів. У цій частині лекції ми розглянемо це питання більш систематизовано і в повному об'ємі. Це дозволить нам безпосередньо перейти до практичних питань програмування на мові асемблера.
2.1. Операнд задається неявно на мікропрограмному рівні (відсутність адресації). В цьому випадку команда явно не містить операндів. Алгоритм виконання команди використовує деякі об'єкти за умовчанням (регістри, прапори в flags і т. д.). Наприклад команди cli і sti неявно працюють з прапором переривання if в регістрі flags, а команда xlat неявно звертається до регістра al і рядку в пам'яті за адресою, визначуваною парою регістрів ds:bx.
2.2. Операнд задається в самій команді (безпосередня адресація). Операнд знаходиться в коді команди, тобто є її частиною. Для зберігання такого операнда в команді виділяється поле завдовжки до 32 біт (див. рис. 3.1). Безпосередній операнд може бути лише другим операндом (джерелом). Операнд-отримувач може знаходитися або в пам'яті, або в регістрі. Наприклад: mov ах,0ffffh пересилає в регістр ах шістнадцяткову константу ffff. Команда add sum,2 додає вміст поля за адресою sum з цілим числом 2 і записує результат по місцю першого операнда, тобто в пам'ять.
2.3. Операнд знаходиться в одному з регістрів (регістрова адресація). Регістрові операнди вказуються іменами регістрів. В якості регістрів можуть використовуватися:
32-розрядні регістри EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP;
16-розрядні регістри AX, BX, CX, DX, SI, DI, SP, BP;
8-розрядні регістри AH, AL, BH, BL, CH, CL, DH, DL;
сегментні регістри CS, DS, SS, ES, FS, GS.
Наприклад, команда add ах,bx додає вміст регістрів ах і bx і записує результат в bx. Команда dec si зменшує вміст si на 1.
2.4. Операнд розташовується в пам'яті. Це найбільш складний і в той же час найбільш гнучкий спосіб завдання операндів. Він дозволяє реалізувати наступні два основні види адресації: пряму і непряму (косвенну).
У свою чергу, косвенна адресація має наступні різновиди:
косвенна базова адресація; інша її назва — регістрова косвенна адресація;
косвенна базова адресація зі зміщенням;
косвенна індексна адресація зі зміщенням;
косвенна базо-індексна адресація;
косвенна базо-індексна адресація зі зміщенням.
2.5. Операндом є порт вводу/виводу. Окрім адресного простору оперативної пам'яті мікропроцесор підтримує адресний простір вводу-виводу, який використовується для доступу до пристроїв вводу-виводу. Об'єм адресного простору вводу-виводу складає 64 Кбайт. Для будь-якого пристрою комп'ютера в цьому просторі виділяються адреси. Конкретне значення адреси в межах цього простору називається портом вводу-виводу. Фізично порту вводу-виводу відповідає апаратний регістр (не плутати з регістром мікропроцесора), доступ до якого здійснюється за допомогою спеціальних команд асемблера in та out. Наприклад, in al,60h ;ввести байт з порту 60h.
Регістри, що адресуються за допомогою порту вводу-виводу, можуть мати розрядність 8, 16 або 32 біт, але для конкретного порту розрядність регістра фіксована.
Команди in і out працюють з фіксованою номенклатурою об'єктів. В якості джерела або одержувача інформації застосовуються так звані регистри-аккумулятори eax, ах, al.
mov dx,20h ;записати номер порту 20h в регістр dx mov al,20h ;записати значення 20h в регістр al out dx,al ;вивести значення 20h в порт 20H |
2.6. Операнд знаходиться в стеку. Команди можуть зовсім не мати операндів, мати один або два операнди. Більшість команд вимагають двох операндів, один з яких є операндом-джерелом, а другий – операндом призначення. Важливе те, що один операнд може розташовуватися в регістрі або пам'яті а другий операнд обов'язково повинен знаходитися в регістрі або безпосередньо в команді. Безпосередній операнд може бути лише операндом-джерелом. У двооперандній машинній команді можливі наступні поєднання операндів:
регістр—регістр;
регістр—пам’ять;
пам’ять—регістр;
безпосередній
операнд—регістр;
безпосередній
операнд—пам’ять.
У даного правила є виключення, які торкаються:
команд роботи з ланцюжками, які можуть переміщати дані з пам'яті в пам'ять;
команд роботи зі стеком, які можуть переносити дані з пам'яті в стек, що також знаходиться в пам'яті;
команд типа множення, які окрім операнда, вказаного в команді, використовують ще і другий, неявний операнд.
З перерахованих поєднань операндів найчастіше вживаються регістр—пам’ять і пам’ять—регістр.
Рис. 3.2 показує, що адреса операнда формується як сума двох складових — зсунутого на 4 біт вмісту сегментного регістра і 16-бітної ефективної адреси, котра в загальному випадку обчислюється як сума трьох компонентів: бази, зміщення та індексу.