Директиви визначення даних

Оперативна пам'ять. Регістри

Оперативна пам'ять. Обсяг оперативної пам'яті ПК - 220 байтів (1 Мб). Байти нумеруються починаючи з 0, номер байта називається його адресою. Для посилань на байти пам'яті використовуються 20-розрядні адреси: від 00000 до FFFFF (у 16-ричной системі). Байт містить 8 розрядів (бітів), кожний з який може приймати значення 1 чи 0. Розряди нумеруються з права наліво від 0 до 7:

Байт - це найменша комірка пам'яті, що може мати адрусу. У ПК використовуються і більш великі комірки - слова і подвійні слова. Слово - це два сусідніх байти, розмір слова - 16 бітів (вони нумеруються з права наліво від 0 до 15). Адресою слова вважається адреса его першого байта (з меншою адресою); ця адреса може бути як парною та і непарною. Подвійне слово - це будь-які чотири сусідніх байти (два сусідніх слова), розмір такої комірки - 32 біта; адресою подвійного слова вважається адреса его першого байта.

Байти використовуються для збереження невеликих цілих чисел і символів, слова - для збереження цілих чисел і адрес, подвійні слова - для збереження "довгих" цілих чисел і адрес у виді сегмент:зсув.

Регістри

Крім комірок оперативної пам'яті для короткочасного збереження даних використовуються регістри - комірки, що входять до складу процесора. Доступ до регістрів здійснюється значно швидше, ніж до комірок пам'яті, тому використання регістрів помітно зменшує час виконання програм. Крім того, у деяких випадках без регістрів узагалі неможливо обійтися.

Усі регістри мають розмір слова (16 бітів), за кожним з них закріплена визначена назва. За призначеням та способом використання регістри можна розбити на наступні групи:

  • регістри загального призначення (AX, BX, CX, DX, BP, SI, DI, SP);
  • сегментні регістри (CS, DS, SS, ES);
  • лічильник команд (IP);
  • регістр ознак (Flags).

Тлумачення цих назв:

  • A accumulator, акумулятор;
  • B base, база;
  • C counter, лічильник;
  • D data, дані;
  • BP base pointer, покажчик бази;
  • SI source index, індекс джерела;
  • DI destination index, індекс приймача;
  • SP stack pointer, покажчик стеку;
  • CS code segment, сегмент команд;
  • DS data segment, сегмент даних;
  • SS stack segment, сегмент стеку;
  • ES extra segment, додатковий сегмент;
  • IP instruction pointer, лічильник команд.

Регістри загального призначення можна використовувати у всіх арифметичних і логічних командах. У той же час кожен з них має визначену спеціалізацію, тобто для деяких команд необхідні тольки визначені регістри. Наприклад, команди множення і ділення вимагають, щоб один з операндів знаходився в регістрі AX чи в регістрах AX і DX (у залежності від розміру операнду), а команди керування циклом використовують регістр CX як лічильник циклу. Регістри BX і BP зазвичай використовуються як базові регістри, а SI і DI - як індексні. Регістр SP як правило вказує на вершину стеку, апаратно підтримуваного ПК.

Регістри AX, BX, CX і DX конструктивно влаштовані так, що можна отримувати доступ до їх старшої і молодшої половин; можна сказати, що кожний з цих регістрів складається з двох регістрів, розмір яких один байт і що позначаються через AH, AL, BH, BL, CH, CL, DH, DL відповідно (H - high, старша; L - low, молодша). Таким чином, з кожним з цих регістрів можна працювати як з єдиним цілим, так і з його частинами. Наприклад, можна записати слово в AX, а потім зчитати тільки частину слова з регістра AH чи замінити тільки частину в регістрі AL і т.д. Така структура регістрів дозволяє використовувати їх для роботи і з числами так і із символами.

Всі інші регістри не оділяються на частині, тому зчитквати чи записувати їхній зміст (16 бітів) можна тільки повністю.

Сегментні регістри CS, DS, SS і ES не можуть бути операндами ніяких команд, окрім стековых команд і команд пересилання. Ці регістри використовуються тільки для сегментування адрес.

Лічильник команд IP завжди містить адресу (зсув від початку програми) тієї команди, що повинна бути виконана наступною (початок програми зберігається в регістрі CS). Зміст регістра IP можна змінити тільки командами переходу.

Ознаки

Процесор має спеціальний регістр ознак. Ознака - це біт, що приймає значення "1", якщо деяку умову було виконано, і значення "0" у іншому випадку. У процесорі i8086 використовуються 9 ознак, кожній з них привласнена визначена назва. Усі вони зібрані в регістрі ознак, тобто кожена ознака - це один з розрядів регістра. Структура регістра ознак зображено на Рис. 1.

Умовно ознаки розділяються на ознаки умов і ознаки станів. Ознаки умов автоматично змінюються при виконанні команд і фіксують ті чи інші властивості їх результату, наприклад, було чи ні переповнення або результат рівний нулю. Ознаки станів встановлюються програмою і визначають подальшу роботу процесора, наприклад, блокують переривання.

x x x x OF DF IF TF SF ZF х AF x PF x CF

Рисунок 1 - Регістр ознак

До ознак умов відносять:

  • CF (carry flag) - ознака переносу. Приймає значення 1, якщо операція призвела до перенесення зі старшого біта результату. Старшим є 7-й, 15-й, 31-й біти в залежності від розмірності операнда. Це відбувається, наприклад, якщо при додаванні цілих чисел результат вийшов за межі розрядної сітки, чи якщо при відніманні чисел без знаку перше з них було менше за друге. У командах зрушення в CF заноситься біт, що вийшов за розрядну сітку;
  • OF (overflow flag) - ознака переповнення. Встановлюється в 1, якщо в результаті операції було виконано перенос у старший, знаковий біт (7-й, 15-й, чи 31-й). Встановлюється в 1, якщо відбувається позика з цих розрядів. Ця ознака необхідна для роботи з числами зі знаком;
  • ZF (zero flag) - ознака нуля. Дорівнює 1, якщо результат операції виявився рівним 0;
  • SF (sign flag) - ознака знаку. Встановлюється в 1, якщо в операції над знаковими числами було отримано від’ємний результат;
  • PF (parity flag) - ознака парності. Дорівнює 1, якщо результат чергової команди містить парну кількість двійкових одиниць. Враховується звичайно при операціях вводу-виводу;
  • AF (auxiliary carry flag) - ознака додаткового переносу. Фіксує особливості виконання операцій над двоїчно-десятковими числами.

До ознак станів відносять:

  • DF (direction flag) - ознака напрямку. Встановлює напрямок перегляду рядків у строкових командах: при DF=0 рядки проглядаються від початку до кінця, при DF=1 - у зворотному напрямку;
  • IF (interrupt flag) - Ознака переривань. При IF=0 процесор перестає реагувати на переривання, що надходять до нього, при IF=1 блокування переривань знімається;
  • TF (trap flag) - ознака трасування. При TF=1 після виконання кожної команди процесор робить переривання (з номером 1), що використовується при налагодженні програми для її трасування (виконання по кроках).

Представлення даних

Розглянемо представлення цілих чисел, рядків і адрес у процесорі i8086. Дійсні числа процесором i8086 не обробляються, операції над цими числами реалізуються програмним шляхом або виконуються співпроцесором. Шістнадцяткові числа записуються з літерою h на кінці, двійкові числа - з літерою b.

У загальному випадку під ціле число можна відвести будь-яку кількість байтів, однак система команд процесора i8086 підтримує числа розміром у байт, слово і подвійне слово.

Розрізняються цілі числа на числа без знаку і знакові цілі числа. В комірках того самого розміру можна розташувати більший діапазон чисел без знаку, чим від’ємних знакових чисел.

Цілі числа без знаку можуть бути представлені у виді байта, слова чи подвійного слова в залежності від їхнього розміру. У виді байта представляються цілі від 0 до 255 (=28-1), у виді слова - цілі від 0 до 65535 (=216-1), у виді подвійного слова - цілі від 0 до 4 294 967 295 (=232-1). Числа записуються в двійковій системі числення, займаючи всі розряди комірки.

10010=64h=0110 0100b (байт)

15010=96h=1001 0110b (байт)

40410=194h=0000 0001 1001 0100b (слово)

61233310=957EDh=0000 0000 0000 1001 0101 0111 1110 1101b (подвійне слово)

Варто відразу зрозуміти особливості збереження слів і подвійних слів у пам'яті комп'ютера. Числа розміром у слово зберігаються в пам'яті в "переверненому" виді: молодші (зправа) 8 бітів числа розміщуються в першому байті слова, а старші 8 бітів - у другому байті (у 16-тковій системі: дві праві цифри - в першому байті, дві ліві цифри - в другому байті). Наприклад, число 30010=012Ch у виді слова зберігається в пам'яті як:

A A+1
2C

Але, якщо це слово завантажити в регістр AX, то його розташування в регістрі буде звичайним:

  AH AL
AX 2C

Аналогічно зберігаються і числа у форматі подвійного слова. У першому его байті розміщаються молодші 8 бітів числа, у другому байті - попередні 8 бітів і т.д. Наприклад, число 12345678h зберігається в пам'яті як:

A A+1 A+2 A+3

У першому слові подвійного слова розміщаються молодші (праві) 16 бітів числа, а в другому слові - старші 16 бітів, причому в кожнім з цих двох слів у свою чергу використовується "перевернене" представлення.

Таке незвичайне представлення чисел викликано тим, що в перших моделях ПК за один раз можна було зчитувати з пам'яті тільки один байт і що всі арифметичні операції над багатозначними числами починаються з дій над молодшими цифрами, тому з пам'яті в першу чергу треба зчитувати молодші цифри, якщо відразу не можна зчитати всі цифри. З огляду на це, у перших ПК і стали розміщати молодші цифри числа перед старшими цифрами, а заради успадкованості таке представлення чисел зберегли й в наступних моделях ПК.

Цілі числа зі знаком також формуються у виді байта, слова і подвійного слова. У виді байта числа записуються від -128 до 127, у вигляді слова - числа від -32768 до 32767, а у вигляді подвійного слова - числа від -2147483648 до 2147483647. При цьому числа записуються в додатковому коді: від’ємне число записується так само, як і беззнакове число (тобто в прямому коді), а від’ємне число -x записується беззнаковим числом 28-x (для байтів), 216-x (для слів) чи 232-x (для подвійних слів). Наприклад, додатковим кодом число (-10) є байт F6h (256-10), слово FFF6h чи подвійне слово FFFFFFF6h. У такий спосіб самий лівий біт інтерпретується як знаковий, якщо він дорівнює 1, то число вважається від’ємним, якщо 0 - позитивним. Якщо знакове ціле число формату байт містить одиницю тольки в знаковому розряді, то воно інтерпретується як -128. Аналогічно для слова це буде -32768, для подвійного слова -2147483648.

Знакові числа розміром у слово і подвійне слово записуються в пам'яті також у "переверненому" виді і знаковим бітом виявляється останій біт байту комірки. Наприклад:

-30010=FED4h

A A+1
D4 FE

-1234567810=FF439EB2

A A+1 A+2 A+3
B2 9E FF

Символи і рядки. На символ відвлдиться один байт пам'яті, у який записується код символу - ціле від 0 до 255. У IBM-сумісних комп'ютерах використовується система кодування ASCII (American Standard Code for Information Interchange).

Деякі особливості цієї системи кодування:

  • код пробілу менше коду будь-якого буквеного символу, цифор й інших символів, що графічно відображаються;
  • коди цифр упорядковані за величиною цифр і не містять пропусків - це від 30h, до 39h;
  • коди великих і малих латинських і букв упорядковані відповідно до алфавіту і не містять пропусків;

Рядок - це послідовність символів, що розміщено в сусідніх байтах пам'яті, код першого символу рядка записується в першому байті, код другого символу - в другому байті і т.д. Адресою рядка вважається адреса його першого байта.

Представлення адрес. Адреса - це порядковий номер комірки пам'яті, тобто від’ємне ціле число, тому в загальному випадку адреси мають вигляд як і беззнакові числа. Часто під адресою розуміється 16-бітовий зсув (offset) - адреса комірки, що знаходиться на відстані “зсув” від початку сегмента (області) пам'яті, якому належить ця комірка. У цьому випадку під адресою розумуєтсья слово пам'яті і як число він записується в пам'яті в "переверненому" виді.

В іншому випадку під адресою розуміється 20-бітова абсолютна адреса деякої комірки пам'яті. Така адреса задається як пара сегмент:зсув, де сегмент (segment) - це перші 16 бітів початкової адреси сегмента пам'яті, якому належить комірка, а зсув - 16-бітова адреса цієї комірки, відносно початку даного сегмента пам'яті. Абсолютна адреса утворюється як сегмент*16+зсув. Такая пари записується в пам'яті у вигляді подвійного слова: у першому слові розміщається зсув, а в другому - сегмент (перевернений вид), причому кожне з цих слів у свою чергу представлено в переверненому виді. Наприклад, пари 1234h:5678h буде записано як:

Зсув Сегмент
       

Директиви визначення даних

Для резервування комірок пам'яті для констант і змінних та їх ініціалізації в мові Асемблера використовуються директиви визначення даних - з назвами DB (визначає дані розміром у байт), DW(визначає дані розміром у слово) і DD (визначає дані розміром у подвійне слово).

Директиви, - це пропозиції програми, за допомогою яких програміст дає додаткові вказівки Асемблеру чи повідомляє йому якусь інформацію, що необхідно для завдання режиму роботи і типу пам'яті, що застосовується, для розміщення програми, стека і даних у пам'яті, резервування й ініціалізації комірок пам'яті, організації зв'язку основної програми з процедурами і т.п.

За допомогою директив DB, DW і DD можуть завдаватись одна чи декілька змінних, привласнюється їм назва. За цією директивою Асемблер формує машинне представлення значень змінних і записує їх у комірки пам'яті по черзі. Адреси цих комірок стають значеннями назв змінних, тобто усі входження назви в програму Асемблер буде заміщувати на відповідну цій назві адресу. Назви, зазначені в директивах DB, DW і DD, називаються назвами змінних. Приклади:

A DB 162 ;Резервування пам'яті для даних розміром 1 байт ;занести в неї число 162 і дати їй назву A B DW -1 ;Виділити пам'ять розміром 2 байти, занести -1 C DD -1 ;Подвійне слово

Дані в директиві DB можуть надаватися як числами, так і как символами: вказується або код символу (ціле від 0 до 255), або сам символ у лапках (одинарних чи подвійних); в останньому випадку Асемблер сам змінить символ на його код. Наприклад, наступні директиви еквівалентні (2A - код знаку * у ASCII):

star DB 02Ah star DB '*' star DB "*"

Якщо адресу необхідно задати як дані, то це робиться так:

star DB '*' adr_star DW star

У цій директиві відведено слово пам'яті, якому надається назва adr_atar і в який запишеться адреса (зсув, ефективна адреса), що відповідає назві star. Якщо для аналогічної мети використовується директива DD:

fadr_star DD star

Асемблер автоматично додасть до зсуву назви його сегмент і запише зсув у першу половину подвійного слова, а сегмент - у другу половину.

По кожній з директив DB, DW і DD можна описати змінну, тобто відвести комірку, не давши їй початкового значення. У цьому випадку в правій частині директиви вказується знак питання:

Param_1 DW ? ;виділити слово, привласнити йому назву Param_1, ;нічого в це слово не записувати

В одній директиві можна описати відразу декілька констант або змінних того самого розміру, для чого їх треба перелічити через кому. Вони розміщуються в сусідніх комірках пам'яті. Приклад:

betta DB 200,-5,10h,?,'F'

Назва, зазначена в директиві, є назвою першого значення. Для посилань на решту в MASM використовуються вираз виду <назва>+<ціле>, наприклад, для доступу до байта з числом -5 використовується вираз betta+1, для доступу до байта зі значенням 10h - вираз betta+2 і т.д. Індексація починається з нуля. Якщо в директиві DB перераховані тілько символи, наприклад:

str DB 'a','b','c'

тоді цю директиву можна записати коротше, уклавши всі ці символи в одні лапки:

str DB 'abc'чи str DB "abc"

Якщо в директиві описується несколько однакових констант (перемінних), то можна скористатися оператором повторення DUP. Наприклад

mas DB 5 dup (4);еквивалентно директиві mas DB 4,4,4,4,4;Інший приклад: arr DW 3 dup (?),-50,2 dup (7);що еквивалентно директиві arr DW ?,?,?,-50,7,7

В Асемблере є директиви EQU і =, за допомогою яких можна визначити константи. Директива EQU привласнює назві значення, що визначається як результат цілочисельного виразу. Директива EQU аналогічна директиві #define у мові Си. Значення, що привласнено назві за допомогою директиви EQU, не можна в змінити.

Приклад:

A equ 10 B equ 21/3 C equ "abcdef"

Директива "=" схожа на директиву EQU, але значення, привласнене назві повинне бути цілим числом і його можна перевизначати. Наприклад:

alfa=20 alfa=alfa+1

Для посилань на поточну комірку використовується позначення $, що є позначенням лічильника поточної адреси. Приклад:

mas DB "assembler" mas_len=$-mas

У цьому прикладі значенням назви mas_len буде довжина рядка mas, тобто число 9.