Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Практикум_СП

.pdf
Скачиваний:
42
Добавлен:
15.02.2015
Размер:
1.01 Mб
Скачать

Відносна непряма адресація (EA = BASE + DISP або INDEX + DISP)

В даному випадку виконувана адреса визначається як сума вмісту регістра бази або регістра індексу із зсувом, що задається константою або символьним ім’ям. Даний режим зручний для доступу до окремих елементів усередині масивів, таблиць, вікон і т.п., при цьому символьне ім’я, якщо воно використовується, визначає початок масиву або таблиці, а вміст регістра задає зсув. Якщо не використовується регістр з константою, то вміст регістра визначає початок оброблюваної області пам’яті, а константа задає зсув. За умовчанням для базового регістра ВХ операнд розміщується в сегменті даних (DS), проте за допомогою префікса заміни сегменту можна вказати будь-який інший сегмент (CS, SS, ЕS). Якщо ж використовується базовий регістр ВР, то операнд за умовчанням передбачається в стековому сегменті (SS), але при необхідності його можна замінити на будь-який інший сегмент (CS,DS, ES).

MOV

[BP+10],0

 

;Обнулити 5-е слово в стеку, якщо

;припускати що BP = SP

 

;Помістити у регістр DX 8-е слово з

MOV

DX,СS: [BХ] + 10Н

;масиву, початок якого

визначено вмістом регістру BХ в сегменті

;коду

String[SI,AL]

;Записати вміст регістр AL в масив

MOV

;байтів на позицію, що

відповідає вмісту регістра SI, рахуючи від

;початку масиву String

в сегменті даних.

Базово-індексна адресація (ЕА = BASE + INDЕХ)

Виконувана адреса при даному режимі адресації виходить у результаті підсумовування вмісту вказаного в команді базового і індексного регістрів. Зазвичай при такій адресації вміст базового регістра указує на початок деякої області пам’яті, а вміст індексного регістра, змінюючись в програмі, ідентифікує окремі елементи або ділянки цієї області. За умовчанням (DS), проте за допомогою префікса заміни сегменту можна вказати будь-який інший сегмент (CS, SS, ES). Якщо ж використовується базовий регістр ВР, то операнд за умовчанням передбачається в стековому сегменті (SS), але при необхідності його можна поміняти на будь-який інший сегмент (CS, DS, ES).

MOV

AX[BX][SI]

;взяти на акумулятор слово з масиву в

;поточному сегменті даних (ВХ = база, SI = зсув)

СMР

AX,ES: [BP][SI]

;та порівняти його із словом на тій

;же позиції масиву в додатковому сегменті даних (ВР - база)

Відносна базово-індексна адресація (EA = BASE + INDEX + DISP)

Цей режим адресації є найбільш складним, хоча б тому що в утворенні виконуваної адреси беруть участь три компоненти: база, індекс і зсув. Ефективно такий режим адресації може застосовуватися, наприклад, для обробки таблиць, коли символьним ім’ям задається початок таблиці, базовим регістром – початок поля в таблиці, а індексним регістром - окремий елемент або ділянка у цьому полі. Якщо ж зсув заданий константою, то зазвичай базовий регістр указує на початок деякої області пам’яті, індексний регістр – на

11

окремий елемент або ділянку цієї області, а константа визначає зсув від цього елементу або ділянки. За умовчанням для базового регістра ВХ операнд передбачається в сегмент даних (DS), проте за допомогою префікса заміни сегменту можна вказати будь-який інший сегмент (CS, SS, ES). Якщо ж використовується базовий регістр ВР, то операнд за умовчанням розташовується в стековому сегменті (SS), але при необхідності його можна поміняти на будь-який інший сегмент (CS, DS, ES).

MOV

AX Data_Table[ BX][S1]

;Переслати

в

АХ слово з

;таблиці,

визначеної

у сегменті даних

під ім’ям Data_Table,

зсув

;слова = BX+SI

 

порівняти

його

з

СМР

ES:Extra_Table[BX][S1],AX

;елементом в тій же

позиції таблиці,

визначеної

в

додатковому

;сегменті під ім’ям Extra_Table

 

 

 

 

 

Адресація стекових операцій

Укомандах стекових операцій один з операндів може бути в регістрі або

впам’яті, що задається одним з розглянутих вище режимів адресації, а другий операнд завжди знаходиться в стековій пам’яті, що задається логічною адресою SS:SP, що завжди неявно визначено самою командою стекової операції. Під час виконання цих команд здійснюється автоматична зміна покажчика стека: SP = SP – 2 (для команди PUSH занесення в стек) або SP = SP + 2 (для команди POP читання зі стеку). В результаті цього покажчик стека SP завжди вказує на верхівку стека. Як покажчик елементів стека можна використовувати і регістр ВР, що дозволяє обробляти їх не за принципом "LIFO – останнім прийшов, першим пішов", а шляхом прямого доступу до потрібного елементу.

PUSH DS

;Зберегти в стеку регістр DS

POP CS:DS_Save

;Прочитати елемент з верхівки стека в

;змінну DS_Save кодового сегменту

Адресація рядкових даних

У командах обробки рядкових даних не використовується жоден з перерахованих вище режимів адресації. При виконанні цих команд неявно визначається, що виконувана адреса операнда-джерела міститься в регістрі SІ, а операнда-приймача – в регістрі DІ. Причому операнд-приймач завжди передбачається в додатковому сегменті (ЕS) і не допускається його перевизначення за допомогою префікса заміни сегменту. Операнд-джерело за умовчанням завантажується у поточний сегмент даних, проте при необхідності його можна перепризначувати у будь-який інший сегмент (СS, ES, SS), використовуючи префікс заміни сегменту. Команди обробки рядкових даних призначені для того, щоб за один раз можна було обробити відразу декілька байт (або слів), тому при їх виконанні відбувається автоматична зміна (збільшення або зменшення) вмісту регістрів-покажчиків SІ і/або DІ. При використанні префікса повторення автоматично змінюється і вміст регістралічильника CX. Слід зазначити, що, оскільки адресація в цих командах визначена неявно, вони мають довжину тільки один байт.

12

REPE

 

;Порівняти

два

ланцюжки байтів

(SI і

DI

CMPSB

на

;указують

порівнювані

байти), поки не вичерпається

лічильник

;(регістр

СХ)

або поки

не

виявиться неспівпадання

 

байтів

в

;операндах

 

;Взяти

слово

з

ланцюжка-джерела

в

сегменті

LODSW

 

;даних (SI = адреса слова)

 

в

ланцюжок-приймач розташоване

в

STOSW

 

;і записати

;додатковому сегменті (DI = адреса слова)

 

 

 

DOS DEBUG

DOS програма з ім'ям DEBUG дозволяє проглядати пам'ять, вводити програми і здійснювати трасування їх виконання.

Для виклику програми DEBUG введіть у командному рядку команду debug, та натисніть Enter, в результаті програма DEBUG повинна завантажитися з диска в пам'ять. Після закінчення завантаження на екрані з'явиться запрошення у вигляді дефіса, що свідчить про готовність програми DEBUG для прийому команд.

Рисунок 2.1 Виведення на екран даних щодо «прошивки» BIOSа

Єдина команда, яка має відношення до даної вправи, це D - для дампу пам'яті.

1. Розмір пам’яті. Спочатку перевіримо розмір доступної для роботи пам'яті. Залежно від моделі комп'ютера це значення пов'язано з установкою внутрішніх перемикачів і може бути менше, чим реально існує. Дане значення знаходиться в елементах пам'яті шіст.413 і 414 і його можна проглянути з DEBUG за адресою, що складається з двох частин:

13

400 - це адреса сегменту, яка записується як 40 (останній нуль мається на увазі) і 13 - це зсув від початку сегменту. Таким чином, можна ввести наступний запит:

D 40:13 (і натиснути Return)

Перші два байти, що з'явилися в результаті на екрані, містять розмір пам'яті в кілобайтах і в «h» уявленні, причому байти розташовуються в зворотній послідовності. Декілька наступних прикладів показують «h». зворотне, «h». нормальне і десяткові уявлення.

2.Серійний номер. Серійний номер комп'ютера "зашитий" у ROM за адресою «h». FE000. Щоб побачити його, слід ввести:

D FE00:0 (і натиснути Return)

В результаті на екрані з'явиться семизначний номер комп'ютера і дата копірайт як показано на рисунку 2.1.

3.Дата ROM BIOS. Дата ROM BIOS у форматі mm/dd/yy знаходиться за «h» адресою FFFF5. Введіть

D FFFF:05 (і натисніть Return)

Для закінчення роботи і виходу з відладчика в DOS введіть команду Q

(Quit). Розглянемо тепер використовування відладчика DEBUG для безпосереднього введення програм в пам'ять і трасування їх виконання.

Для наочного прикладу виконання команди трасування введіть текст лістингу програми, збережіть його під ім’ям minus.asm, відкомпілюйте та скомпонуйте його.

page

60,132

(СОМ) Складання та віднімання

TITLE

EXADD

CODESG

SEGMENT

PARA 'Code'

 

 

ASSUME

CS:CODESG,DS:CODESG,SS:CODESG

BEGIN:

ORG

100H

 

JMP

SHORT MAIN

 

; --------------------------------------------

DB

64H

;Елементи даних

BYTEA

BYTEB

DB

40H

 

BYTEC

DB

16H

 

WORDA

DW

4000H

 

WORDB

DW

2000H

 

WORDC

DW

1000H

 

; --------------------------------------------

PROC

NEAR

;Основна процедура:

MAIN

 

CALL

B10ADD

;Викликати складання ADD

 

CALL

C10SUB

;Викликати віднімання SUB

MAIN

RET

 

 

ENDP

 

 

;Приклад складання байтів:

 

B10ADD

PROC

AL,BYTEA

 

 

MOV

 

 

MOV

BL,BYTEB

;Регістр і регістр

 

ADD

AL,BL

 

ADD

AL,BYTEC

;Пам’ять і регістр

 

ADD

BYTEA,BL

;Регістр і пам’ять

 

ADD

BL,10H

;Безпосеред. і регістр

14

 

ADD

BYTEA,25H

;Безпосеред. і пам’ять

B10ADD

RET

 

 

ENDP

 

 

;Приклад віднімання слів:

 

C10SUB

PROC

AX,WORDA

 

 

MOV

 

 

MOV

BX,WORDB

;Регістр із регістру

 

SUB

AX,BX

 

SUB

AX,WORDC

;Пам’ять із регістру

 

SUB

WORDA,BX

;Регістр із пам’яті

 

SUB

BX,1000H

;Безпосеред. із peг.

 

SUB

WORDA,256H

;Безпосеред. із пам.

C10SUB

RET

 

 

ENDP

 

 

CODESG

ENDS

BEGIN

 

 

END

 

Тепер введіть таку команду: Debug minus.asm. Після чого на екрані з’явиться символ «-», що свідчить про те, що програма готова приймати команди від користувача. Щоб побачити покроково, які операції виконуватиме програма – оберіть команду трасування «-t», та натисніть Enter. Повторіть операцію декілька разів. У результаті на екрані з’явиться вміст регістрів, як показано на рисунку 2.2. Команда -t, дозволяє продивитися як відбувається трасування та як змінюється вміст регістрів, при виконанні процесором чергової команди з вище приведеним лістингом програми.

Рисунок 2.2 Приклад виконання команди трасування.

15

Контрольні питання

1.У яких сегментах можуть знаходитися оброблювані програмою дані і чим при цьому визначається їх адреса?

2.Яким способом можна визначити вікно в стеку і який з режимів адресації найбільш ефективний для доступу до окремих елементів в цьому вікні?

3.Як можна схематично зобразити спосіб формування виконуваної адреси для непрямої, відносної непрямої, базово-індексної і відносної базовоіндексною адресацій?

4.Чи можна визначити стек в кодовому сегменті або ланцюговоприймача в сегменті даних?

5.Скільки і які регістри необхідно підготувати для виконання ланцюгової команди, що працює з двома операндами і префіксом повторення?

6.Яким чином виконується перевірка розміру пам’яті, серійного номеру та дати ROM BIOS вашого комп’ютера?

Індивідуальні завдання

1.Написати програму обнулення масиву слів завдовжки 100 елементів, використовуючи всі можливі режими адресації.

2.Написати програму пересилки масиву байтів завдовжки 256 елементів

вінший масив такої ж довжини, використовуючи всі можливі режими адресації.

3.Написати програму, яка переписує вміст змінної Tmp_Type (довжина 15 байтів) у полі Type елементів таблиці з прикладу 3.

4.Написати програму, яка побудує стек наступного змісту:

Адреса Z

<-----SP

Адреса Y

Адреса X, а потім, використовуючи роботу з вікном стека, виконає операцію Z = X + Y. Змінні X, Y і Z являють собою подвійні слова.

16

Практична робота № 3

Тема: Система команд. Команди обробки даних.

Мета роботи: Вивчення способів представлення і обробки різних типів числових даних, використовуваних в асемблерних програмах.

Теоретичні відомості

У системі команд мікропроцесора x86 є команди для безпосереднього виконання арифметичних операцій над двійковими, двійково-десятковими числами (упакований BCD-формат) і десятковими числами в символьних кодах ASCII (неупакований BCD-формат). Двійкові числа можуть інтерпретуватися як числа із знаком або як числа в беззнаковому уявленні, при цьому ті та інші можуть мати різну довжину в пам'яті: байт, слово або декілька байтів/слів (багатократна точність). Числа в BCD-форматі представляються в байті, і зазвичай потрібно декілька байтів для представлення необхідного числового значення. Нижче показані структури представлення числової інформації і відповідні їм діапазони:

байт:7.........0

двійкове без знаку

0...255

 

|

|

 

 

7.........0

 

двійкове із знаком

-128...+127

 

|S

|

 

 

7.........0

 

BCD-формат (2 цифри) 00...99

 

| |

|

 

 

7.........0

ASCII-формат (1 цифра)

0...9

слово

|

|

 

:15...................0

двійкове без знаку

0...65365

 

|

 

 

|

 

 

15...................0

 

двійкове із знаком

-32768...+32767

 

|

 

 

|

 

 

Двійкові

числа

із знаком

представляються доповненням до двох,

внаслідок чого самий старший розряд (S) є знаковим: 0 = +, 1 + -. При такому уявленні, якщо розширюється число розрядів для представлення числа, то вони заповнюються значенням знакового розряду, на відміну від двійкових чисел без знаку, для яких вони заповнюються нулем. При виконанні операції над двійковими числами результат може вийти більшим, ніж допустимий діапазон. Ця ситуація фіксується прапорцем CF для двійкових чисел без знаку і прапорцем 0F для двійкових чисел із знаком. У разі багатократної точності прапор CF в тому і іншому випадку використовується для передачі біта перенесення від молодших до старших розрядів. Для складання і віднімання двійкових чисел із знаком і без знаку використовують одні і ті ж команди ADD або відповідно SUB, а для багатократної точності використовуються ще і команди, що враховують перенесення (ADC) при складанні або заєм (SBB) при відніманні:

17

Помилка

Помилка

Помилка

ADC

ADC

ADD

++ +

Помилка SBB заєм SBB заєм SBB

Як видно з приведених схем, у разі складання або віднімання з підвищеною точністю CF = 1 після складання або віднімання самих старших розрядів позначає помилку (переповнювання). При складанні або відніманні двійкових чисел із знаком, представлених ланцюжком слів або байтів, схема виконання операції та ж, тільки ознакою виходу результату за межі допустимого діапазону служить 0F = 1 після складання або віднімання самих старших розрядів. Слід зазначити, що для таких чисел корисними можуть бути і команди CBW (байт AL > слово AX) і CWD (слово AX > подвійне слово DX : AX). По приведених вище схемах реалізуються і операції складання і віднімання десяткових чисел в BCD-форматі, представлених послідовністю байтів, тільки в даному випадку операція повинна обов'язково здійснюватися побайтно через акумулятор AL і після кожної операції складання (або віднімання) потрібно виконувати операцію корекції результату DAA (або відповідно DAS). У приведеному нижче фрагменті програми ілюструються способи реалізації операцій складання і віднімання для двійкових чисел і для десяткових чисел в BCD-форматі. При використанні команд порівняння CMP необхідно враховувати, що вони не змінюють операндів, а тільки встановлюють прапорці після їх віднімання, при цьому порівняння чисел без знаку і із знаком вимагає правильного підбору команд умовного переходу, оскільки якщо, наприклад AL = -1 і AH = 127, то

CMP

AL,AH

;без знаку: AL

=

11111111b

> AH = 01111111b

JA

Above

JL

Less

;із знаком: AL

=

-1 < AH =

+127

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

S_OP1

DW

 

 

;Визначення початкових операндів

-15683, 25670, 127

;48-розрядне двійкове ціле

S_OP2

DW

-2459, 65535, 4569

;48-розрядне двійкове ціле

B_OP1

DB

29H, 34H, 98H, 51H, 37H, 45H

;12-розрядне BCD-число

 

 

 

B_OP2

DB

19H, 60H, 07H, 68H, 78H, 47H

;12-розрядне BCD-число

 

 

 

;Місце для запису результатів

(?)

;S_OP1 + S_OP2

UA_RESL

DW

3

DUP

US_RESL

DW

3

DUP

(?)

;S_OP1 - S_OP2

BA_RESL

DB

6

DUP

(?)

;B_OP1 + B_OP2

BS_RESL

DB

6

DUP

(?)

;B_OP1 - B_OP2

;

;Складання двійкових чисел без знаку (і із знаком)

18

;

AX,S_OP1 + 4

 

;починаючи

 

 

MOV

 

 

 

ADD

AX,S_OP2 + 4

 

;з молодших розрядів

MOV

UA_REDL + 4,AX

 

;складаємо спочатку без

MOV

AX,S_OP1 + 2

 

;а потім

 

 

 

ADC

AX,S_OP2+2

 

;з урахуванням перенесення

MOV

UA_RESL +2,AX

 

;і записуємо результат

MOV

AX,S_OP1

;якщо операнди розглядаються

ADD

AX,S_OP2

;як числа без знаку

1

позначає

MOV

UA_RESL,AX

;то

CF

=

;переповнювання, якщо ж вони розглядаються як числа із знаком, то ;0F = 1 позначає переповнення

; Віднімання двійкових чисел без знаку (і із знаком)

MOV

AX,S_OP1 + 4

;починаючи

 

 

SUB

AX,S_OP2 + 4

;з молодших розрядів

 

MOV

UA_REDL + 4,AX

;складаємо спочатку без

 

MOV

AX,S_OP1 + 2

;а потім

 

 

SBB

AX,S_OP2 + 2

;з урахуванням заєма

 

MOV

UA_RESL +2,AX

;і записуємо результат

 

MOV

AX,S_OP1

 

;якщо операнди розглядаються

SBB

AX,S_OP2

 

;як числа без знаку

переповнення,

MOV

UA_RESL,AX

;то CF =

1 позначає

;якщо ж

вони розглядаються як числа із

знаком, то 0F

= 1 позначає

;переповнювання

 

 

 

 

;

 

 

 

 

 

; Поміняти знак операнда S_OP1 = -S_OP1

 

 

;

S_OP1

 

;інвертуємо

 

 

NOT

 

 

 

NOT

S_OP1 + 2

 

;усі

 

 

NOT

S_OP1 + 4

 

;розряди

 

 

ADD

S_OP1 + 4,1

;а потім +1 до наймолодшого біта

ADC

S_OP1 + 2,0

;і облік можливого перенесення

ADC

S_OP1,0

 

;для решти розрядів

 

;

 

 

 

 

 

; Порівняння двійкових чисел без знаку (і із знаком)

 

;

AX,S_OP1 + 4

;починаючи

 

 

MOV

 

 

SUB

AX,S_OP2 + 4

;з молодших розрядів

 

MOV

BX,AX

 

;віднімаємо спочатку без

 

MOV

AX,S_OP1 + 2

;а потім

 

 

SBB

AX,S_OP2 + 2

;з урахуванням заєма

 

OR

BX,AX

;результат в BX потрібен тільки для порівняння

MOV

AX,S_OP1

 

;перехід виконуватиметься

SBB

AX,S_OP2

 

;для чисел:

 

JA

Above

 

;без знаку, якщо S_OP1 > S_OP2

JB

Below

 

;або S_OP1 < S_OP2

 

JG

Greater

 

;із знаком

якщо S_OP1 > S_OP2

JL

Less

 

;або S_OP1 < S_OP2

 

OR

BX,AX

;для обох випадків перевірка на співпадання

JZ

Equal

;рівність однакова: S_OP1 = S_OP2

 

;

;Складання десяткових чисел упакованого BCD-формату

19

;

SI,5

;встановити покажчик на самий мол. байт

MOV

MOV

CX,6

 

;лічильник на кількість байтів

CLC

 

 

;і прапор CF в нуль

 

;Цикл складання, корекції і запису результату

 

Nxt_Add: MOV AL,B_OP1[S1]

;взяти байт 1-го операнда

ADC

AL,B_OP2[S1]

;скласти

з

відповідним байтом 2-го і

;перенесенням

 

; скоректувати

 

 

 

DAA

B_RESL[S1],AL

 

 

 

MOV

;і записати результат

 

DEC

S1

 

;встановити покажчик на наступний байт

LOOP

Nxt_Add

 

;продовжувати

до

вичерпання

зчитування

;байтів, якщо CF = 1, то переповнювання

 

 

;

 

 

 

 

 

 

 

;Віднімання десяткових чисел упакованого BCD-формату

 

;

SI,5

;встановити покажчик на самий молодший байт

MOV

MOV

CX,6

 

;лічильник на кількість байтів

CLC

 

 

;і прапор CF в нуль

 

;Цикл віднімання, корекції і запису результату

 

Nxt_Sub MOV AL,B_OP1[S1] ;узяти байт 1-го операнда

 

SBB

AL,B_OP2[S2]

;відняти відповідний байт 2-го і позику

DAS

B_RESL[S1],AL

;скоректувати

 

 

MOV

;і записати результат

 

DEC

S1

 

;встановити покажчик на наступний байт

LOOP

Nxt_Sub

 

;продовжувати

до

вичерпання

;зчитування байтів, якщо CF = 1, те переповнювання

Для двійкових чисел із знаком і без знаку є відповідні команди множення і ділення (IMUL, IDIV і MUL, DIV). Команди множення (IMUL, MUL) дозволяють умножати байт в AL на байт в регістрі або пам'яті і отримати результат у вигляді слова в AX або умножати слово в AX на слово в регістрі або пам'яті і отримати результат у вигляді подвійного слова в регістрах DX і AX. При використанні команди IMUL операнди і результат є числами із знаком, а у разі команди MUL – вони обробляються як беззнакові двійкові величини. За допомогою команд ділення (IDIV, SIV) можна ділити слово в AX на байт в регістрі або пам'яті і одержати частку в AL і залишок в AH або розділити подвійне слово в DX, AX на слово в регістрі або пам'яті і одержати частку у AX і залишок у DX. При використанні команди IDIV операнди і результат обробляються як двійкові числа із знаком, а у разі команди DIV - як числа без знаку. При діленні можливо переповнювання, якщо частка перевищує допустимий діапазон або якщо дільник дорівнює нулю. У будь-якому випадку ця ситуація викликає переривання по нульовому вектору, при обробці якого DOS видає повідомлення "Dividing Overflow" і аварійно завершує виконання програми. Якщо це небажано, то програміст повинен перед виконанням ділення перевірити можливість переповнювання або використовувати свою процедуру обробки переповнювання при діленні. Перевірити можливість переповнювання можна через порівняння старших розрядів діленого з дільником: якщо вони більше, ніж дільник (для чисел із знаком перевіряються абсолютні значення), то

20